C#反射调用拓展类
小紫苏 人气:0今天封装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);
运行结果:
总结
加载全部内容