C#反射調(diào)用拓展類方法實(shí)例代碼
今天封裝Protobuf封包時(shí)候遇到一個(gè)問題;
Protobuf的反序列化方法MergeFrom,是寫在擴(kuò)展類里的;
C# 類拓展方法
要求:
擴(kuò)展方法類必須為靜態(tài)類;
拓展方法必須為靜態(tài)方法,參數(shù)為this+需拓展類對(duì)象;
多個(gè)類拓展方法可以寫在一個(gè)拓展類中;
public class TestExtension { public string Test1() { return "test"; } } public static class MyExtension { public static void Show(this TestExtension obj) { Debug.Log("ExtensionFunc:"+ obj.Test1()); } }
調(diào)用:
TestExtension ts = new TestExtension(); ts.Show();
通過反射獲取不到這個(gè)方法,就沒法使用Type來泛型封裝...
然而仔細(xì)一想,拓展類不也是類嗎,直接反射獲取拓展類方法好了;
C#反射調(diào)用拓展類
在看Google.Protobuf源碼,找到這個(gè)類;
這個(gè)MergeFrom方法就是需要的;
那這個(gè)IMessage接口怎么辦;
所有自動(dòng)生成的protobuf類都只自動(dòng)繼承兩個(gè)接口;
所以傳需要序列化的類即可;
//接收到服務(wù)器消息;反序列化后執(zhí)行相應(yīng)路由方法 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}"); //打印傳輸獲得的字節(jié)的utf-8編碼 PrintUTF8Code(bytes); Type tp = typeof(Google.Protobuf.MessageExtensions); //反射獲取拓展類方法MergeFrom MethodInfo method = ReflectTool.GetExtentMethod(tp,"MergeFrom", protoType, typeof(byte[])); //反射創(chuàng)建實(shí)例,回調(diào)方法 object obj = ReflectTool.CreateInstance(protoType); ReflectTool.MethodInvoke(method, obj, obj, bytes); sEvents.Enqueue(new KeyValuePair<Type, object>(protoType, obj)); }
ProtoDic存儲(chǔ)了protoId和對(duì)應(yīng)的類型Type;
ReflectTool.GetExtentMethod——封裝了GetMethod方法,為了能連續(xù)傳入多個(gè)參數(shù),而不是傳Type數(shù)組;
ReflectTool.MethodInvoke——和上面目的一樣;
//獲取擴(kuò)展方法 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創(chuàng)建實(shí)例,返回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; }
最后寫測(cè)試代碼:
pb.BroadCast結(jié)構(gòu)為:
message BroadCast{ int32 PID =1; int32 Tp = 2; string Content = 3; }
運(yùn)行代碼:
Pb.BroadCast bo = new Pb.BroadCast(); bo.PID = 1; bo.Tp = 1; bo.Content = "Perilla"; byte[] res = bo.ToByteArray(); //打印字節(jié)的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);
運(yùn)行結(jié)果:
總結(jié)
到此這篇關(guān)于C#反射調(diào)用拓展類方法的文章就介紹到這了,更多相關(guān)C#反射調(diào)用拓展類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c# 連接access數(shù)據(jù)庫(kù)config配置
c# 連接access數(shù)據(jù)庫(kù)config配置,需要的朋友可以參考一下2013-02-02C#實(shí)現(xiàn)基于ffmpeg加虹軟的人臉識(shí)別的示例
本篇文章主要介紹了C#實(shí)現(xiàn)基于ffmpeg加虹軟的人臉識(shí)別的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10Qt之調(diào)用C#的動(dòng)態(tài)庫(kù)的解決方法
這篇文章給大家介紹了Qt之調(diào)用C#的動(dòng)態(tài)庫(kù)的解決方法,環(huán)境使用的是VS2019+Qt5.12,感興趣的朋友一起看看吧2021-10-10在WPF中動(dòng)態(tài)加載XAML中的控件實(shí)例代碼
這篇文章主要介紹了在WPF中動(dòng)態(tài)加載XAML中的控件,實(shí)例分析了WPF中針對(duì)XAML中控件的動(dòng)態(tài)調(diào)用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07C#中自定義高精度Timer定時(shí)器的實(shí)例教程
這篇文章主要介紹了C#中自定義高精度Timer定時(shí)器的實(shí)例教程,多線程的Timer編寫需要注意線程安全的問題,需要的朋友可以參考下2016-04-04WPF利用LiveCharts實(shí)現(xiàn)動(dòng)態(tài)曲線圖繪制
LiveCharts是一個(gè)比較漂亮的WPF圖表控件,在數(shù)據(jù)發(fā)生變化后,還可以設(shè)置相對(duì)于的動(dòng)畫效果,本文就來利用LiveCharts繪制簡(jiǎn)單的動(dòng)態(tài)曲線圖吧2023-10-10