C# 使用特性的方式封裝報文

来源:https://www.cnblogs.com/fengxinyuan/p/18363546
-Advertisement-
Play Games

在編寫上位機軟體時,需要經常處理命令拼接與其他設備進行通信,通常對不同的命令封裝成不同的方法,擴展稍許麻煩。 本次擬以特性方式實現,以兼顧維護性與擴展性。 思想: 一種命令對應一個類,其類中的各個屬性對應各個命令段,通過特性的方式,實現其在這包數據命令中的位置、大端或小端及其轉換為對應的目標類型; ...


在編寫上位機軟體時,需要經常處理命令拼接與其他設備進行通信,通常對不同的命令封裝成不同的方法,擴展稍許麻煩。

本次擬以特性方式實現,以兼顧維護性與擴展性。


思想:

一種命令對應一個類,其類中的各個屬性對應各個命令段,通過特性的方式,實現其在這包數據命令中的位置、大端或小端及其轉換為對應的目標類型;

然後通過反射對其進行拼包,從而得到一包完整數據。

場景:

將一個軸移動到對應的X,Y,Z位置,為了演示,對其共用一個速度

這個移動到指定位置的命令假設按以下順序構成(為了展示,草率的命令結構):

序號 1 2 3 4 5 6 7 8 9
位元組 2 s32 u16 u16 u32 s32 s32 s32 2
說明 包頭 步驟號(ID) 功能碼 速度 X位置 Y位置 Z位置 包尾

 

 

 


 

實現:

創建特性 CmdPropertyAttribute 

 1 [AttributeUsage(AttributeTargets.Property)]
 2 internal class CmdPropertyAttribute : Attribute
 3 {
 4     public Type? TargetType { get; set; }
 5 
 6     public int Number { get; set; }
 7 
 8     public bool IsReverse { get; set; }
 9 
10     public CmdPropertyAttribute(int number)
11     {
12         Number = number;
13     }
14 
15     public CmdPropertyAttribute(int number, Type targetType)
16     {
17         Number = number;
18         TargetType = targetType;
19     }
20 
21     public CmdPropertyAttribute(int number, bool isReverse)
22     {
23         Number = number;
24         IsReverse = isReverse;
25     }
26 
27     public CmdPropertyAttribute(int number, Type targetType, bool isReverse)
28     {
29         Number = number;
30         IsReverse = isReverse;
31         TargetType = targetType;
32     }
33 }

參數類,每一種命令對應一個參數類,它們繼承於參數基類

創建參數基類  ParamBase ,每種數據都是步驟號處於第一位,特把其放入到基類中

1     public class ParamBase
2     {
3         [CmdProperty(0, true)]
4         public int StepNum { get; set; }
5     }

創建軸枚舉  Axis 

1     public enum Axis : ushort
2     {
3         Axis_1 = 1,
4 
5         Axis_2 = 2,
6     }

創建功能碼枚舉  FunctionCode 

1     public enum FunctionCode
2     {
3         Move = 1
4     }

創建移動類  MoveParam ,為了更好展示高低位轉換,特對Speed屬性進行反轉

 1     public class MoveParam : ParamBase
 2     {
 3         [CmdProperty(1, typeof(ushort))]
 4         public FunctionCode Function { get; init; }
 5 
 6         [CmdProperty(2, typeof(ushort))]
 7         public Axis Axis { get; set; }
 8 
 9         [CmdProperty(3, true)]
10         public uint Speed { get; set; }
11 
12         [CmdProperty(4)]
13         public int XPoint { get; set; }
14 
15         [CmdProperty(5)]
16         public int YPoint { get; set; }
17 
18         [CmdProperty(6)]
19         public int ZPoint { get; set; }
20 
21         public MoveParam()
22         {
23             Function = FunctionCode.Move;
24         }
25 
26         public MoveParam(int stepNum, Axis axis, uint speed, int xPoint, int yPoint, int zPoint)
27         {
28             Function = FunctionCode.Move;
29             StepNum = stepNum;
30             Axis = axis;
31             Speed = speed;
32             XPoint = xPoint;
33             YPoint = yPoint;
34             ZPoint = zPoint;
35         }
36     }

對參數對象進行反射解析,生成對應的數據命令集合

創建擴展類  ParamBaseExtensions 

 1     public static class ParamBaseExtensions
 2     {
 3         public static byte[] ToCmd(this ParamBase param)
 4         {
 5             var properties = param.GetType().GetProperties()
 6                 .Where(x => x.IsDefined(typeof(CmdPropertyAttribute), false))
 7                 .OrderBy(x => ((CmdPropertyAttribute)x.GetCustomAttribute(typeof(CmdPropertyAttribute))).Number);
 8 
 9             List<byte> result = new();
10 
11             foreach (var item in properties)
12             {
13                 var cmdAttribute = item.GetCustomAttribute(typeof(CmdPropertyAttribute)) as CmdPropertyAttribute;
14 
15                 var value = item.GetValue(param);
16 
17                 if (cmdAttribute.TargetType is not null)
18                 {
19                     value = Convert.ChangeType(value, cmdAttribute.TargetType);
20                 }
21 
22                 var propertyBytes = value.ToBytes();
23 
24                 if (cmdAttribute.IsReverse)
25                     propertyBytes = propertyBytes.Reverse().ToArray();
26 
27                 result.AddRange(propertyBytes);
28             }
29 
30             return result.ToArray();
31         }
32 
33 
34         private static byte[] ToBytes(this object obj)
35         {
36             return obj switch
37             {
38                 short s => BitConverter.GetBytes(s),
39                 ushort s => BitConverter.GetBytes(s),
40                 int s => BitConverter.GetBytes(s),
41                 uint s => BitConverter.GetBytes(s),
42                 float s => BitConverter.GetBytes(s),
43                 double s => BitConverter.GetBytes(s),
44                 byte s => [s],
45                 _ => throw new NotImplementedException(),
46             };
47         }
48     }

將數據命令與包頭,包尾拼接,從而組合成一包完整數據

創建類  CmdHelper 

 1     public class CmdHelper
 2     {
 3         private byte[] GetHeads()
 4         {
 5             return [0x0B, 0x0F];
 6         }
 7 
 8 
 9         private byte[] GetTails()
10         {
11             return [0x0C, 0x0A];
12         }
13 
14         public byte[] BuilderCmd(ParamBase param)
15         {
16             return
17                 [
18                     .. GetHeads(),
19                     .. param.ToCmd(),
20                     .. GetTails(),
21                 ];
22         }
23     }

調用:

 1 var cmdHelper = new CmdHelper();
 2 var param = new MoveParam()
 3 {
 4     XPoint = 14,
 5     YPoint = 14,
 6     ZPoint = 14,
 7     Axis = Enums.Axis.Axis_1,
 8     Speed = 20,
 9     StepNum = 1
10 };
11 var byteArr = cmdHelper.BuilderCmd(param);
12 
13 foreach (var item in byteArr) 
14 {
15     Console.Write(item.ToString("X2") + " ");
16 }

最後的列印結果為:

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  特性即可

 

本文來自博客園,作者:逸羽瀾心,轉載請註明原文鏈接:https://www.cnblogs.com/fengxinyuan/p/18363546


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Torna —— 一款介面文檔解決方案,目標是讓介面文檔管理變得更加方便、快捷。採用團隊協作的方式管理和維護介面文檔,將不同形式的文檔納入進來統一維護。 ...
  • 大多數的業務場景下 PHP 還沒有達到性能瓶頸,然而 MySQL 資料庫就先行駕崩了。但我們總是不分青紅皂白,一股腦的把原因歸結於是 PHP 語言不行了,每當遇到這種情形我就會感嘆到 PHP 的命真苦啊。 ...
  • 大家好,我是曉凡。 寫在前面 不知道大家有沒有做財務的朋友,我就有這麼一位朋友就經常跟我抱怨。一到月底簡直就是噩夢,總有加不完的班,熬不完的夜,做不完的報表。 一聽到這兒,這不就一活生生的一個“大表哥”麽,這加班跟我們程式員有得一拼了,忍不住邪惡一笑,心裡平衡了很多。 身為牛馬,大家都不容易啊。我不 ...
  • 目錄Razor 類庫創建使用使可路由組件可從 RCL 獲取靜態資源表單EditForm標準輸入組件驗證HTML 表單 Razor 類庫 這裡只對 RCL 創建和使用的做一些簡單的概述,詳細內容參考官方文檔 使用 Razor 類庫 (RCL) 中的 ASP.NET Core Razor 組件。 創建 ...
  • 泛型(Generics)是C#中的一個重要特性,它允許您編寫靈活、類型安全且可重用的代碼。下麵我將詳細介紹泛型的概念、使用方法及其在C#中的實現細節。 泛型的基本概念 1. 什麼是泛型? 泛型是一種允許您定義類型參數的機制,這些類型參數可以在編譯時由具體的類型替換。這樣,您可以編寫一個通用的類或方法 ...
  • VS常用拓展以及快捷鍵 擴展1:Select Next Occurrence 該拓展可以當前目標、下一個目標、上一個目標,類似於Alt+滑鼠拖動,但是可以在沒對齊的情況下使用 安裝 設置4個常用的快捷鍵 工具->選項->鍵盤->c# 2005 選擇下一個 快捷鍵:Ctrl+D 選擇上一個 快捷鍵:C ...
  • 編程編的久了,總會遇到多線程的情況,有些時候我們要幾個線程合作完成某些功能,這時候可以定義一個全局對象,各個線程根據這個對象的狀態來協同工作,這就是基本的線程同步。 支持多線程編程的語言一般都內置了一些類型和方法用於創建上述所說的全局對象也就是鎖對象,它們的作用類似,使用場景有所不同。.Net中這玩 ...
  • 我們.NET開發會引用很多外部Nuget包,多項目、多個解決方案、甚至多個倉庫。 簡單的Nuget包管理,通過VS就能比較簡單處理好。但複雜的場景呢,比如: 1.一個倉庫里,有多個解決方案的Nuget包管理 -- 我現在項目就是這樣的,針對會議大屏的全家桶軟體集代碼倉庫。這個倉庫里,接近30個工具/ ...
一周排行
    -Advertisement-
    Play Games
  • 前言 推薦一款基於.NET 8、WPF、Prism.DryIoc、MVVM設計模式、Blazor以及MySQL資料庫構建的企業級工作流系統的WPF客戶端框架-AIStudio.Wpf.AClient 6.0。 項目介紹 框架採用了 Prism 框架來實現 MVVM 模式,不僅簡化了 MVVM 的典型 ...
  • 先看一下效果吧: 我們直接通過改造一下原版的TreeView來實現上面這個效果 我們先創建一個普通的TreeView 代碼很簡單: <TreeView> <TreeViewItem Header="人事部"/> <TreeViewItem Header="技術部"> <TreeViewItem He ...
  • 1. 生成式 AI 簡介 https://imp.i384100.net/LXYmq3 2. Python 語言 https://imp.i384100.net/5gmXXo 3. 統計和 R https://youtu.be/ANMuuq502rE?si=hw9GT6JVzMhRvBbF 4. 數 ...
  • 本文為大家介紹下.NET解壓/壓縮zip文件。雖然解壓縮不是啥核心技術,但壓縮性能以及進度處理還是需要關註下,針對使用較多的zip開源組件驗證,給大家提供個技術選型參考 之前在《.NET WebSocket高併發通信阻塞問題 - 唐宋元明清2188 - 博客園 (cnblogs.com)》講過,團隊 ...
  • 之前寫過兩篇關於Roslyn源生成器生成源代碼的用例,今天使用Roslyn的代碼修複器CodeFixProvider實現一個cs文件頭部註釋的功能, 代碼修複器會同時涉及到CodeFixProvider和DiagnosticAnalyzer, 實現FileHeaderAnalyzer 首先我們知道修 ...
  • 在軟體行業,經常會聽到一句話“文不如表,表不如圖”說明瞭圖形在軟體應用中的重要性。同樣在WPF開發中,為了程式美觀或者業務需要,經常會用到各種個樣的圖形。今天以一些簡單的小例子,簡述WPF開發中幾何圖形(Geometry)相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 在 C# 中使用 RabbitMQ 通過簡訊發送重置後的密碼到用戶的手機號上,你可以按照以下步驟進行 1.安裝 RabbitMQ 客戶端庫 首先,確保你已經安裝了 RabbitMQ 客戶端庫。你可以通過 NuGet 包管理器來安裝: dotnet add package RabbitMQ.Clien ...
  • 1.下載 Protocol Buffers 編譯器(protoc) 前往 Protocol Buffers GitHub Releases 頁面。在 "Assets" 下找到適合您系統的壓縮文件,通常為 protoc-{version}-win32.zip 或 protoc-{version}-wi ...
  • 簡介 在現代微服務架構中,服務發現(Service Discovery)是一項關鍵功能。它允許微服務動態地找到彼此,而無需依賴硬編碼的地址。以前如果你搜 .NET Service Discovery,大概率會搜到一大堆 Eureka,Consul 等的文章。現在微軟為我們帶來了一個官方的包:Micr ...
  • ZY樹洞 前言 ZY樹洞是一個基於.NET Core開發的簡單的評論系統,主要用於大家分享自己心中的感悟、經驗、心得、想法等。 好了,不賣關子了,這個項目其實是上班無聊的時候寫的,為什麼要寫這個項目呢?因為我單純的想吐槽一下工作中的不滿而已。 項目介紹 項目很簡單,主要功能就是提供一個簡單的評論系統 ...