上周五,下了班,老板找我让我把C#里的串口类(SerialPort)封装下,我当时没多想,封装就封装呗,反正这事儿我没干过,摸石头过河,顺便锻炼下自己的技术。周日没事儿,写了点儿。可写到datareceived的时候写不下去了。因为牵扯到协议的原因,实际使用的时候,SerialPort的datareceived都是自己实现的。这就意味着我得定义一个接口,使用的时候,还得继承我写的这个类,然后再对继承后的类实例化,然后才能使用。这兜了一大圈子又回来了,这不是白白的浪费了么。请大家积极发言,讨论下封装类的常规做法和封装c#的SerialPort类有无实际意义。

解决方案 »

  1.   

    没搞过这事    serialport也没用过
      

  2.   

    对了 我们用serialport类 实现收发短信
      

  3.   

    以前做web,现在web做的少,主要做串口和以太网通讯。封装的目的是为了简化操作,端口肯定是可设置的,协议就是写一个方法把16进制代码翻译并容错就OK了。但是,我感觉封装这个类没有多大的实际意义。
      

  4.   

    我们公司短信这块儿不是我做的。专门做CDMA的同事写下位机,另一位写C++和Delphi的同事写上位机。
    我现在配合着用c#写点儿小程序。
      

  5.   

    是啊,我就是感觉没有封装的必要了 。现在我只是把表示16进制数据的字符串和字节数组之间的转换以及CRC16\CRC32\累加和校验这几个常用的方法加进去。但是越来越感觉这么做没实际意义。是在做无用功。
      

  6.   

    技术上:
    个人觉得没有必要。
    还不如把这几个方法写好,每次去调用呢。
    这样,debug时也方便纠错。工作中:
    还是很有必要的,老板的话永远是对的。如果某天他觉得不好用,你再给拆了也不费时。
      

  7.   

    我觉得应该是把协议和端口连接封装一下比如:
    方法
    ExecuteCommand
    //从上位机接收命令,然后发送到下位机。
    //将参数按照规则转换为byte[]事件
    HaveSomeData
    //接收到下位机数据,通知上位机。
    //将byte[]转换为结构或者类。这样下位机与上位机没有任何的直接关联。
    封装产生的类,相当于一个翻译程序。
    不同的协议可以用派生类实现。
      

  8.   

    他要简化串口操作,以后只关心协议的实现。但是我感觉SerialPort类本身就已经很不错了,无需封装。
      

  9.   

     你的老板说的很有道理啊,简化串口操作,以后只关心协议的实现,这样以后再写的话就只关心实现了,不用再考虑具体的读写串口具体细节
    接口不用定义,使用Action<>或Func<>就行
      

  10.   


    我觉得封装很有必要
    SerialPort类本身之提供了串口的通信,如果你们公司自己有自己的通信协议,你封装的目的就是把自己的通信协议写进去。比如你说的CRC16,CRC32之类。
    比如你们自己的协议里规定0x0d,0x0e是数据结尾,那么你就可以根据这个,等整个一个数据包都收完了再触发数据接收完成的事件,而不需要一个byte触发一次。
    这样别人用你封装好的方法,接受到的就是完整的包,不需要自己再做其他处理了
      

  11.   

    汗,协议就不用封装进去了。因为又不是一个设备在研发。老板的意思是要把SerialPort类封装下,这样以后开发串口通讯软件的时候,只需要关注协议的实现。但是我感觉SerialPort类就目前我使用的情况来看,够用了。
      

  12.   

    封装是有用的,我就是把 SerialPort 封装起来,实现同步或异步通讯, 而且还可以在 加一个解析类后, 就可以 指定 接收帧 是按固定长度发送的还是 在帧内包括数据长度 ...还可以抽出 一个通用接口, TCP通讯也可以实现这个接口, 这样可以做到与具体的通讯方式无关!总之,   封装还是有很多好处的。不过, 主要要看你的应用了。
      

  13.   

    SerialPort类本身之提供了串口的通信,如果你们公司自己有自己的通信协议,你封装的目的就是把自己的通信协议写进去。
      

  14.   

    还有像  walkghost 说的,协议必须与具体的通讯方式分离, 我的实现是:ICommunication 通讯接口
    SerialPortBase : ICommunication
    {
       
    }
    TCPClientBase : ICommunication
    {
        
    }IProtocal  协议接口
    {
       ICommunication Communication{
          get;
        }
    }
      

  15.   

    这倒是个不错的想法,只要实现通信就OK了。可以把串口、TCP/IP都封装进来。用户与具体的通信方式无关。不错不错,我们有些产品室通过以太转串口实现的上位机和下位机通信。另外,我想把我的16进制字符串和字节数组之间转换的俩方法贴出来,有一个是在网上找的,希望大家批评指正。
      

  16.   


     #region 字符串和字节数组相互转换
            /// <summary>
            /// 将字符串转换成16进制字节数组,并自动在字节数组后面加cs校验和
            /// </summary>
            /// <param name="_data">要转换的string</param>
            /// <param name="byteArray">转换之后的字节数组</param>
            /// <returns>为空则表示执行正确,否则,表示错误信息</returns>
            public static string ChangeHexStringToByteArray(string _data, out byte[] byteArray)
            {
                string sResult = "";
                byteArray = null;
                if (_data == "")
                {
                    sResult = "请不要传入空值。函数:ChangeHexStringToByteArray。";
                }
                else if (_data.Length % 2 != 0)
                {
                    sResult = "请传入正确的十六进制字符串,字符串的个数必须是偶数个。函数:ChangeHexStringToByteArray。";
                }
                else
                {
                    try
                    {
                        _data = _data.Replace(" ", "");
                        int sendLength = _data.Length / 2;
                        byteArray = new byte[sendLength];
                        string hexstring = "";
                        int k = 0;
                        for (int i = 0; i < _data.Length; )
                        {
                            hexstring = _data.Substring(i, 2);
                            int j;
                            j = int.Parse(hexstring, System.Globalization.NumberStyles.HexNumber);
                            byteArray[k] = (byte)j;
                            i += 2;
                            k++;
                        }
                    }
                    catch (Exception ex)
                    {
                        sResult = ex.Message;
                    }
                }
                return sResult;
            }
            /// <summary>
            /// 将字节数组转换成十六进制字符串
            /// </summary>
            /// <param name="data">要转换的字节数组</param>
            /// <param name="HexString">转换后的字符串</param>
            /// <returns>为空则表示执行正确,否则,表示错误信息</returns>
            public static string ChangeByteArrayToHexString(byte[] data, out string HexString)
            {
                string sResult = "";
                HexString = "";
                StringBuilder sb = new StringBuilder(data.Length * 3);
                try
                {
                    foreach (byte b in data)
                        sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
                }
                catch (Exception ex)
                {
                    sResult = "将字节数组转换成字符串时出错,函数:ChangeByteArrayToHexString。异常信息:" + ex.Message;
                }
                HexString = sb.ToString().ToUpper();
                return sResult;
            }        #endregion
      

  17.   

    计算校验和这一块儿看起来有点儿繁琐,主要是先对字符串进行转换,然后对字节数组进行计算。现实编程中我喜欢拼凑16进制字符串而非字节形式的 0xff,0x00之类的。        #region 计算校验和
            /// <summary>
            /// 对16进制数字的进行CRC16校验,然后把校验值返回
            /// </summary>
            /// <param name="str">要进行校验的数据</param>
            /// <param name="CRC16Result">校验值(校验结果)</param>
            /// <returns>为空则表示执行正确,否则,表示错误信息</returns>
            public string GetCRC16ResultByHexString(string str,string CRC16Result)
            {
                ushort crcResult;
                byte[] byArr;
                string sResult = "";
                CRC16Result = "";
                try
                {
                    sResult = ChangeHexStringToByteArray(str, out byArr);
                    if ((sResult == "") && (byArr != null))
                    {
                       sResult= CalculateCRC(byArr, byArr.Length, out crcResult);
                       if (sResult == "")
                       {
                           ushort h = (byte)(crcResult & 0xFF);
                           ushort l = (byte)((crcResult & 0xFF00) >> 8);
                           string height = Convert.ToString(h, 16);
                           string low = Convert.ToString(l, 16);
                           if (height.Length == 1)
                               height = height.Insert(0, "0");
                           if (low.Length == 1)
                               low = low.Insert(0, "0");
                           CRC16Result = low.ToUpper() + height.ToUpper();
                       }
                    }
                }
                catch (Exception ex)
                {
                    sResult += ex.Message;
                }            return sResult;
            }        /// <summary>
            /// crc16算法
            /// </summary>
            /// <param name="pByte">要校验的字节数组</param>
            /// <param name="nNumberOfBytes">字节个数</param>
            /// <param name="pChecksum">校验结果</param>
            /// <returns>为空则表示执行正确,否则,表示错误信息</returns>
            public static string CalculateCRC(byte[] pByte, int nNumberOfBytes, out ushort pChecksum)
            {
                int nBit;
                ushort nShiftedBit;
                pChecksum = 0xFFFF;
                string sResult = "";
                if (nNumberOfBytes > pByte.Length)
                {
                    sResult = "传入的参数nNumberOfBytes(字节个数)大于pByte(要校验的字节数组)的长度";
                }
                else
                {
                    try
                    {
                        for (int nByte = 0; nByte < nNumberOfBytes; nByte++)
                        {
                            pChecksum ^= pByte[nByte];
                            for (nBit = 0; nBit < 8; nBit++)
                            {
                                if ((pChecksum & 0x1) == 1)
                                {
                                    nShiftedBit = 1;
                                }
                                else
                                {
                                    nShiftedBit = 0;
                                }
                                pChecksum >>= 1;
                                if (nShiftedBit != 0)
                                {
                                    pChecksum ^= 0xA001;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        sResult = ex.Message;
                    }
                }
                return sResult;
            }
            /// <summary>
            /// 计算累加校验和
            /// </summary>
            /// <param name="SendByteArray">要校验的字节数组</param>
            /// <returns>对字节数组进行校验所得到的校验和</returns>
            public static byte GetSumCS(byte[] SendByteArray)
            {
                byte rst = 0x00;            
                //计算累加和
                for (int j = 2; j < SendByteArray.Length; j++)
                {
                    unchecked
                    {
                        rst += SendByteArray[j];
                    }
                }
                //累加和计算结束
                return rst;
            }
            #endregion
      

  18.   

    挺好  不过我不会 怎么办  我现在也在做  用C#  写一个和设备端的串口传输协议,这个设备是厂家新近生产出来的  没有开发设备端RAPI(因为是新出来的)  所以我就得自己去实现了  真难啊
      

  19.   

    这个想法估计有很多人也有吧,只是到目前为止好像没看到一个完整(COM,TCP、等这类全为一体)的类哦,