首页 > 编程语言 >C# 使用特性的方式封装报文

C# 使用特性的方式封装报文

时间:2024-08-23 09:54:29浏览次数:10  
标签:00 封装 get C# 报文 CmdPropertyAttribute int public Axis

在编写上位机软件时,需要经常处理命令拼接与其他设备进行通信,通常对不同的命令封装成不同的方法,扩展稍许麻烦。

本次拟以特性方式实现,以兼顾维护性与扩展性。


思想

一种命令对应一个类,其类中的各个属性对应各个命令段,通过特性的方式,实现其在这包数据命令中的位置、大端或小端及其转换为对应的目标类型;

然后通过反射对其进行拼包,从而得到一包完整数据。

场景

将一个轴移动到对应的X,Y,Z位置,为了演示,对其共用一个速度

这个移动到指定位置的命令假设按以下顺序构成(为了展示,草率的命令结构):

序号123456789
字节2s32u16u16u32s32s32s322
说明包头步骤号(ID)功能码速度X位置Y位置Z位置包尾


实现

创建特性 CmdPropertyAttribute 

[AttributeUsage(AttributeTargets.Property)]
internal class CmdPropertyAttribute : Attribute
{
    public Type? TargetType { get; set; }

    public int Number { get; set; }

    public bool IsReverse { get; set; }

    public CmdPropertyAttribute(int number)
    {
        Number = number;
    }

    public CmdPropertyAttribute(int number, Type targetType)
    {
        Number = number;
        TargetType = targetType;
    }

    public CmdPropertyAttribute(int number, bool isReverse)
    {
        Number = number;
        IsReverse = isReverse;
    }

    public CmdPropertyAttribute(int number, Type targetType, bool isReverse)
    {
        Number = number;
        IsReverse = isReverse;
        TargetType = targetType;
    }
}

参数类,每一种命令对应一个参数类,它们继承于参数基类

创建参数基类  ParamBase ,每种数据都是步骤号处于第一位,特把其放入到基类中

      public class ParamBase
      {
          [CmdProperty(0, true)]
          public int StepNum { get; set; }
      }

创建轴枚举  Axis 

public enum Axis : ushort
    {
        Axis_1 = 1,

        Axis_2 = 2,
    }

创建功能码枚举  FunctionCode 

      public enum FunctionCode
      {
          Move = 1
      }

创建移动类  MoveParam ,为了更好展示高低位转换,特对Speed属性进行反转

public class MoveParam : ParamBase
    {
        [CmdProperty(1, typeof(ushort))]
        public FunctionCode Function { get; init; }

        [CmdProperty(2, typeof(ushort))]
        public Axis Axis { get; set; }

        [CmdProperty(3, true)]
        public uint Speed { get; set; }

        [CmdProperty(4)]
        public int XPoint { get; set; }

        [CmdProperty(5)]
        public int YPoint { get; set; }

        [CmdProperty(6)]
        public int ZPoint { get; set; }

        public MoveParam()
        {
            Function = FunctionCode.Move;
        }

        public MoveParam(int stepNum, Axis axis, uint speed, int xPoint, int yPoint, int zPoint)
        {
            Function = FunctionCode.Move;
            StepNum = stepNum;
            Axis = axis;
            Speed = speed;
            XPoint = xPoint;
            YPoint = yPoint;
            ZPoint = zPoint;
        }
    }

对参数对象进行反射解析,生成对应的数据命令集合

创建扩展类  ParamBaseExtensions 

public static class ParamBaseExtensions
    {
        public static byte[] ToCmd(this ParamBase param)
        {
            var properties = param.GetType().GetProperties()
                .Where(x => x.IsDefined(typeof(CmdPropertyAttribute), false))
                .OrderBy(x => ((CmdPropertyAttribute)x.GetCustomAttribute(typeof(CmdPropertyAttribute))).Number);

            List<byte> result = new();

            foreach (var item in properties)
            {
                var cmdAttribute = item.GetCustomAttribute(typeof(CmdPropertyAttribute)) as CmdPropertyAttribute;

                var value = item.GetValue(param);

                if (cmdAttribute.TargetType is not null)
                {
                    value = Convert.ChangeType(value, cmdAttribute.TargetType);
                }

                var propertyBytes = value.ToBytes();

                if (cmdAttribute.IsReverse)
                    propertyBytes = propertyBytes.Reverse().ToArray();

                result.AddRange(propertyBytes);
            }

            return result.ToArray();
        }


        private static byte[] ToBytes(this object obj)
        {
            return obj switch
            {
                short s => BitConverter.GetBytes(s),
                ushort s => BitConverter.GetBytes(s),
                int s => BitConverter.GetBytes(s),
                uint s => BitConverter.GetBytes(s),
                float s => BitConverter.GetBytes(s),
                double s => BitConverter.GetBytes(s),
                byte s => [s],
                _ => throw new NotImplementedException(),
            };
        }
    }

将数据命令与包头,包尾拼接,从而组合成一包完整数据

创建类  CmdHelper 

public class CmdHelper
    {
        private byte[] GetHeads()
        {
            return [0x0B, 0x0F];
        }


        private byte[] GetTails()
        {
            return [0x0C, 0x0A];
        }

        public byte[] BuilderCmd(ParamBase param)
        {
            return
                [
                    .. GetHeads(),
                    .. param.ToCmd(),
                    .. GetTails(),
                ];
        }
    }

调用:

var cmdHelper = new CmdHelper();
var param = new MoveParam()
{
    XPoint = 14,
    YPoint = 14,
    ZPoint = 14,
    Axis = Enums.Axis.Axis_1,
    Speed = 20,
    StepNum = 1
};
var byteArr = cmdHelper.BuilderCmd(param);

foreach (var item in byteArr)
{
    Console.Write(item.ToString("X2") + " ");
}

最后的打印结果为:

0B 0F 00 00 00 01 00 00 01 00 00 00 00 14 0E 00 00 00 0E 00 00 00 0E 00 00 00 0C 0A

如果后续在写其他命令,只需继承于  ParamBase 类,在对应的属性上使用  CmdProperty  特性即可

标签:00,封装,get,C#,报文,CmdPropertyAttribute,int,public,Axis
From: https://blog.csdn.net/qq_43648978/article/details/141456275

相关文章

  • CNN-BiLSTM-Attention(12种算法优化CNN-BiLSTM-Attention多输入单输出)
     12种算法优化CNN-BiLSTM-Attention模型预测的代码。其中Attention模型可以改为单头或者多头,在代码中就是改个数字而已。代码注释已写好如何更改。12种算法优化CNN-BiLSTM-Attention多特征输入单步预测代码获取戳此处代码获取戳此处代码获取戳此处主要功能为:采用12种......
  • 做思维导图?chatmoney轻轻松松拿下
    本文由ChatMoney团队出品嘿,各位职场朋友们是不是常常对着密密麻麻的笔记感到焦虑呢?想整理却无从下手?别怕,ChatmoneyAI知识库来拯救你的整理困难症啦!咱们都知道,思维导图是职场中必备的神器它能帮我们理清思路,记忆知识但传统做法嘛,不是画得乱七八糟就是费时费力,真心不方便......
  • ICCEMDAN+皮尔逊+小波分解降噪+重构
    ICEEMDAN+皮尔逊+小波分解降噪+重构代码获取戳此处ICEEMDAN(改进的CEEMDAN)原理:ICEEMDAN是由Colominas等人提出的信号处理方法,它是在自适应噪声完全集合经验模态分解(CEEMDAN)的基础上发展而来。与CEEMDAN不同,ICEEMDAN在分解过程中不是直接添加高斯白噪声,而是选取白噪声被E......
  • CDGA|数据治理:解锁各行业数据驱动业务发展的新篇章
    在当今这个数字化时代,数据已成为企业最宝贵的资产之一,其蕴含的价值远超传统资源。有效的数据治理不仅能够帮助企业提升运营效率、优化决策过程,还能驱动业务创新,为企业在激烈的市场竞争中赢得先机。本文将探讨不同行业如何利用数据治理策略来驱动业务发展,展现数据作为核心驱动力......
  • Infisical怎么在Jenkins内调用
    参考https://infisical.com/docs/integrations/cicd/jenkins#jenkins-pluginJenkins参考https://plugins.jenkins.io/infisical/前提条件安装配置infisical设置了项目和密钥Infisical创建身份认证创建身份AccessControl->MachineIdentities->Createidentify......
  • rancher 篇
    rancher磁盘负载警告问题原因:在查看pod运行状态时,发现有的pod的状态是Evicted,通过describe去查看发现了Thenodehadcondition:[DiskPressure].的报错原因是kubelet检测到本地磁盘使用率超过了85%,这是kubelet的默认配置查看根目录下(/)使用率是否超过85%。......
  • Windows 10 美化 Mac OSX 实用教程
    我前几天给新电脑装上了Windows10系统,想要美化一下,遇到了很多问题,就出了这篇博客,帮大家踩踩坑。在开始之前,先提醒大家一句:美化有风险,玩机需谨慎。为以防万一,请大家在进行任何操作前创建一个系统还原点。首先给大家避避坑,千万别用Steam,不挂梯子根本下载不了,美化资源基本上都要......
  • devexpress gridview master,detail视图 focuseRowHandle 同步选中
    gridview1是主视图,gridview2是其子视图gridview1中的多行就对应了多个gridview2实例,那么通时展开多个gridview1中的多个行,并且在这些展开的行中点不同gridview2的行时,gridview1的焦点行是不会自动切换的的需要做如下处理(这里还包括了了gridview2中的checkboxedit)......
  • wiz 为知笔记服务器 docker 跨服务器迁移爬坑指北
    本文主要是介绍wiz为知笔记服务器docker从旧服务器迁移到新服务器的步骤以及问题排查。旧服务器升级wizdocker目的:保持和新服务器拉取的镜像版本一致。官方只留了wizdocker镜像最新版,拉取不了旧版本镜像,所以先升级旧服务器上的wizdocker。升级方法dockerstopwiz......
  • 拖拽神器:Pragmatic-drag-and-drop!
    前言在前端开发中,拖拽功能是一种常见的交互方式,它能够极大提升用户体验。今天,我们要介绍的是一个开源的前端拖拽组件—pragmatic-drag-and-drop,它以其轻量级、高性能和强大的兼容性,成为了前端开发者的新宠。什么是pragmatic-drag-and-drop?pragmatic-drag-and-drop是由A......