使用Mono.Cecil给消息类自动添加Attribute

C#的序列化库很多通过注解Attribute来实现,比如Protobuf-net,Messagepack等。如果手动添加注解,会比较麻烦,尤其在切换序列化库的时候,需要更改对应的注解。
这里实现了一个使用Mono.Cecil来自动添加注解的类,当程序编译后,会修改对应的dll来实现效果。

遇到的坑:IDE对于IL级别的错误没有充分清晰的错误提示,需要自己折腾一会儿,去花时间排查问题。【比如注解应该加在Property上的,加在了Field上 /doge】


public class CecilUser
    {

        public static void Work(string fileName)
        {
            using (var module = ModuleDefinition.ReadModule(fileName, new ReaderParameters { ReadWrite = true }))
            {
                // Modify the assembly
                foreach (TypeDefinition type in module.Types)
                {
                    if (!type.IsPublic)
                        continue;
                    if (!type.IsClass)
                        continue;

                    if (ContainsAttribute(type.CustomAttributes, nameof(MessagePackObjectAttribute)))
                        continue;


                    ModifyType(module, type);

                }

                module.Write(); // Write to the same file that was used to open the file
            }
        }

        public static bool ContainsAttribute(Collection<CustomAttribute> attrCollection, string attributeName)
        {
            foreach (var typeAttr in attrCollection)
            {
                if (typeAttr.AttributeType.FullName.Contains(attributeName))
                    return true;
            }
            return false;
        }

        private static void ModifyType(ModuleDefinition module, TypeDefinition type)
        {
            MethodReference classAttrCtor = module.ImportReference(typeof(MessagePackObjectAttribute).GetConstructor(new Type[] { typeof(bool) }));
            var typeAttr = new CustomAttribute(classAttrCtor);
            var boolTypeRef = module.ImportReference(typeof(bool));
            var attrParamType = new CustomAttributeArgument(boolTypeRef, false);
            typeAttr.ConstructorArguments.Add(attrParamType);
            type.CustomAttributes.Add(typeAttr);

            int keyIndex = 0;

            foreach(var property in type.Properties)
            {
                if (ContainsAttribute(property.CustomAttributes, nameof(KeyAttribute)))
                    continue;

                MethodReference fieldAttrCtor = module.ImportReference(typeof(KeyAttribute).GetConstructor(new Type[] { typeof(int) }));

                var attr = new CustomAttribute(fieldAttrCtor);
                var intTypeRef = module.ImportReference(typeof(int));
                var attrParam = new CustomAttributeArgument(intTypeRef, keyIndex++);
                attr.ConstructorArguments.Add(attrParam);

                property.CustomAttributes.Add(attr);
            }

        }


    }
posted @   dewxin  阅读(107)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示