今天封裝Protobuf封包時候遇到一個問題;
Protobuf的反序列化方法MergeFrom,是寫在擴充套件類裡的;c#擴充類
通過反射獲取不到這個方法,就沒法使用Type來泛型封裝...
然而仔細一想,擴充類不也是類嗎,直接反射獲取擴充類方法好了;
在看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);
執行結果: