網站首頁 編程語言 正文
今天封裝Protobuf封包時候遇到一個問題;
Protobuf的反序列化方法MergeFrom,是寫在擴展類里的;
C# 類拓展方法
要求:
擴展方法類必須為靜態類;
拓展方法必須為靜態方法,參數為this+需拓展類對象;
多個類拓展方法可以寫在一個拓展類中;
public class TestExtension { public string Test1() { return "test"; } } public static class MyExtension { public static void Show(this TestExtension obj) { Debug.Log("ExtensionFunc:"+ obj.Test1()); } }
調用:
TestExtension ts = new TestExtension(); ts.Show();
通過反射獲取不到這個方法,就沒法使用Type來泛型封裝...
然而仔細一想,拓展類不也是類嗎,直接反射獲取拓展類方法好了;
C#反射調用拓展類
在看Google.Protobuf源碼,找到這個類;
這個MergeFrom方法就是需要的;
那這個IMessage接口怎么辦;
所有自動生成的protobuf類都只自動繼承兩個接口;
所以傳需要序列化的類即可;
//接收到服務器消息;反序列化后執行相應路由方法 public void DispatchProto(int protoId, byte[] bytes) { if (!ProtoDic.ContainProtoId(protoId)) { Logger.LogError($"Unkown ProtoId:{protoId}"); return; } Type protoType = ProtoDic.GetProtoTypeByProtoId(protoId); Logger.Log($"protoId:{protoId};--typeName:{protoType.FullName}"); //打印傳輸獲得的字節的utf-8編碼 PrintUTF8Code(bytes); Type tp = typeof(Google.Protobuf.MessageExtensions); //反射獲取拓展類方法MergeFrom MethodInfo method = ReflectTool.GetExtentMethod(tp,"MergeFrom", protoType, typeof(byte[])); //反射創建實例,回調方法 object obj = ReflectTool.CreateInstance(protoType); ReflectTool.MethodInvoke(method, obj, obj, bytes); sEvents.Enqueue(new KeyValuePair<Type, object>(protoType, obj)); }
ProtoDic存儲了protoId和對應的類型Type;
ReflectTool.GetExtentMethod——封裝了GetMethod方法,為了能連續傳入多個參數,而不是傳Type數組;
ReflectTool.MethodInvoke——和上面目的一樣;
//獲取擴展方法 public static MethodInfo GetExtentMethod(Type extentType, string methodName, params Type[] funcParams) { MethodInfo method = GetMethod(extentType, methodName, funcParams); return method; } public static object MethodInvoke(MethodInfo method, object obj, params object[] parameters) { return method.Invoke(obj, parameters); }
//通過Type創建實例,返回Object public static object CreateInstance(Type refType, params object[] objInitial) { object res = System.Activator.CreateInstance(refType, objInitial); if (res == null) { Logger.LogError($"Reflect create Type:{refType.FullName} is null"); } return res; }
最后寫測試代碼:
pb.BroadCast結構為:
message BroadCast{ int32 PID =1; int32 Tp = 2; string Content = 3; }
運行代碼:
Pb.BroadCast bo = new Pb.BroadCast(); bo.PID = 1; bo.Tp = 1; bo.Content = "Perilla"; byte[] res = bo.ToByteArray(); //打印字節的utf-8編碼 StringBuilder strBuilder = new StringBuilder(); for (int i = 0; i < res.Length; ++i) { strBuilder.Append(res[i]); strBuilder.Append('-'); } Logger.Log(strBuilder.ToString()); Pb.BroadCast bo2 = new Pb.BroadCast(); bo2.MergeFrom(res); Logger.LogFormat("{0}=={1}=={2}", bo2.PID, bo2.Tp, bo2.Content);
運行結果:
總結?
原文鏈接:https://www.cnblogs.com/littleperilla/p/15830746.html
相關推薦
- 2022-11-02 Python+eval函數實現動態地計算數學表達式詳解_python
- 2022-12-23 Kubernetes有狀態應用管理StatefulSet使用詳解_云其它
- 2022-09-04 C語言中反斜杠的作用及說明_C 語言
- 2022-04-01 安裝k8s Error initializing network controller: Error
- 2022-08-23 python3.7安裝matplotlib失敗問題的完美解決方法_python
- 2022-11-10 詳解C++?左值引用與?const?關鍵字_C 語言
- 2022-09-21 python?Flask框架之HTTP請求詳解_python
- 2022-11-06 YOLOv5改進系列之增加小目標檢測層_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支