当前位置:首页 > Web开发 > 正文

显然这么一个一个的加attributes既费时又容易出错

2024-03-31 Web开发

第二次发博客,但愿大家多多鼓励!!!

又接无上老板的一个需求,需要让.net core动静发送端跟动静接收端通信的动静是protobuf格局的(基于protobuf比json小一倍数据量,奇特的编码、没有fieldname等),但现有项目的动静类数量巨多,凭据网上的方案是安置protobuf.net 这个nuget包,然后需要给动静类一个一个添加[ProtoBuf.ProtoContract]、[ProtoBuf.ProtoMember(index)]等Attributes,更可悲的是,还得措置惩罚惩罚担任的问题,也就是要有类似如下这种代码:

[ProtoContract] [ProtoInclude(10, typeof(Male))] public class Person { [ProtoMember(1)] public int Id { get; set; } [ProtoMember(2)] public string Name { get; set; } [ProtoMember(3)] public Address Address { get; set;} } [ProtoContract] public class Male : Person { } [ProtoContract] public class Address { [ProtoMember(1)] public string Line1 {get;set;} [ProtoMember(2)] public string Line2 {get;set;} }

关于为什么要设置上面这些attributes,跟protobuf的道理息息相关,有兴趣的伴侣可以看看这篇文章,而关于protobuf.net的根基用法,可以参考这里

找解决方案,咱们不干体力活

对付项目存在巨多动静类,显然这么一个一个的加attributes既费时又容易堕落。我拿着这个需求,,怀着忐忑的心,一通操纵,终于找到了想要的方案,也就是找到了without attributes的要领,趁便暗暗的报告您,貌似国内还没谁发明这个要领

使用RuntimeTypeModel.Default进行类型及其Properties的配置

动动脑筋,上面的代码,如果不用attributes而是用RuntimeTypeModel.Default进行类型及其Properties的配置的话,代码就是的:

var personMetaType = RuntimeTypeModel.Default.Add(typeof (Person), false); personMetaType.Add(1, "Id"); personMetaType.Add(2, "Name"); personMetaType.Add(3, "Address"); var addressMetaType = RuntimeTypeModel.Default.Add(typeof(Address), false); addressMetaType.Add(1, "Line1"); addressMetaType.Add(2, "Line2"); // 给父类metaType添加子类型 personMetaType.AddSubType(10, typeof (Male)); // 然后添加子类型 RuntimeTypeModel.Default.Add(typeof(Male), false); RuntimeTypeModel.Default.Add(typeof(Female), false);

但是仔细想想其实道理跟添加attributes是一个原理,

具体实现

有了上面这个要领,我们就会自然而然想到对所有动静类使用RuntimeTypeModel.Default进行类型及其Properties的配置,但我们又不成能费时吃力的给项目的每个动静实体类添加这些代码,那么这里就想到了使用反射找出项目中所有动静实体类,然后一个一个的操纵

先看看我们的动静基类:

/// <summary> /// 使用MQ行列队伍的动静基类 /// </summary> public class MsgBase { /// <summary> /// 动静编码、接入系统编码 /// </summary> public string MessageCode { get; set; } /// <summary> /// 动静类型 (业务相关的一个枚举) /// </summary> public MessageTypeCode MessageType { get; set; } }

很简单吧,然后看看我们给类动态添加“[ProtoBuf.*]”这些attributes的核心代码:

static bool isInit = false; // 制止反复初始化 /// <summary> /// 初始化,动静发送跟措置惩罚惩罚措施在启动后就需要挪用 /// </summary> public static void Init() { if (!isInit) { var msgAssemblyName = "Msg Model 地址的 assemly long name"; // 需要措置惩罚惩罚MsgBase自己跟担任它的所有动静类型 var msgTypes = (from t in Assembly.Load(msgAssemblyName).GetTypes() where (t.BaseType == typeof(MsgBase) || t.Name == "MsgBase") select t).OrderBy(t=>t.Name).ToList(); foreach (var msgType in msgTypes) { AddTypeToModel(msgType, RuntimeTypeModel.Default); } isInit = true; } } /// <summary> /// 添加类型以及字段到模型中 /// </summary> /// <param name="type"></param> /// <param name="typeModel"></param> /// <returns></returns> private static void AddTypeToModel(Type type, RuntimeTypeModel typeModel) { if (typeModel.IsDefined(type)) { return; } typeModel.IncludeDateTimeKind = true; // 1. 进行类型配置 var metaType = typeModel.Add(type, true); // Protobuf的挨次很重要,在序列化跟反序列化都需要连结一致的挨次,否则反序列化的时候就会堕落 var publicProperties = type.GetProperties().Where(h => h.SetMethod != null).OrderBy(h => h.Name); var complexPropertiesInfo = publicProperties.Where(f => !IsSimpleType(f.PropertyType)).OrderBy(h=>h.Name); // 2. 进行此类型的Properties的配置 foreach (var simplePropertyInfo in publicProperties) { metaType.Add(simplePropertyInfo.Name); } // 庞大类型需要措置惩罚惩罚里面的每个简单类型,使用了递归操纵 foreach (var complexPropertyInfo in complexPropertiesInfo) { if (complexPropertyInfo.PropertyType.IsGenericType) { // Protobuf的挨次很重要,在序列化跟反序列化都需要连结一致的挨次,否则反序列化的时候就会堕落 foreach (var genericArgumentType in complexPropertyInfo.PropertyType.GetGenericArguments().OrderBy(h=>h.Name)) { if (!IsSimpleType(genericArgumentType)) { AddTypeToModel(genericArgumentType, typeModel); } } } else { AddTypeToModel(complexPropertyInfo.PropertyType, typeModel); } } } /// <summary> /// 是否为简单类型 /// </summary> /// <param name="type"></param> /// <returns></returns> private static bool IsSimpleType(Type type) { var underlyingType = Nullable.GetUnderlyingType(type); var newType = underlyingType ?? type; var simpleTypes = new List<Type> { typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal), typeof(bool), typeof(string), typeof(char), typeof(Guid), typeof(DateTime), typeof(DateTimeOffset), typeof(byte[]), typeof(string[]) }; return simpleTypes.Contains(newType) || newType.GetTypeInfo().IsEnum; }

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/31123.html