Fody跨程序集属性复制异常:如何实现不同程序集间属性复制
跨程序集复制属性特性的解决方案
问题背景
我在做AOP织入处理时,逻辑是遍历类、属性及其特性:当识别到MetaAttribute(typeof(SomethingElse))特性时,找到SomethingElse类中名为Target的属性,把它的所有特性复制到当前处理模块中对应类的属性上。比如Person类的Title属性标注了[Meta(typeof(PersonTitleMeta))],而PersonTitleMeta的Target属性带有Required、MinimumLength等特性,需要把这些特性复制到Person.Title上。
当PersonTitleMeta和Person在同一程序集时,用这段代码可以正常运行:
foreach (var currentSourceAttribute in sourceAttributes) property.CustomAttributes.Add(currentSourceAttribute);
但二者在不同程序集时,会报错:System.ComponentModel.DataAnnotations.RequiredAttribute::.ctor()' is declared in another module and needs to be imported。
解决思路
不能直接跨模块复制已有的CustomAttributeData实例,因为它绑定了原模块的构造函数引用。正确的做法是基于原特性的元数据,在目标模块中重新构造特性实例:
具体实现步骤
- 获取原特性的类型与构造函数信息:从源特性的
Constructor属性拿到构造函数的MethodBase,再在目标模块可访问的范围内找到对应的构造函数(可通过Type.GetType获取特性类型后再匹配构造函数参数)。 - 转换构造函数参数:遍历源特性的
ConstructorArguments,将参数值转换成目标模块能识别的形式——值类型直接复用,引用类型需确保目标模块已引用对应类型所在程序集。 - 处理命名参数:遍历源特性的
NamedArguments,同样转换参数值,确保目标模块能解析这些参数对应的属性或字段。 - 添加新特性到目标属性:用目标模块的特性构建API(比如
CustomAttributeBuilder),基于上述信息创建新特性并绑定到目标属性上。
代码示例
foreach (var sourceAttr in sourceAttributes) { // 获取特性类型 var attrType = sourceAttr.AttributeType; // 在目标模块中匹配对应的构造函数 var targetCtor = attrType.GetConstructor( sourceAttr.Constructor.GetParameters().Select(p => p.ParameterType).ToArray()); // 提取并转换构造函数参数 var ctorArgs = sourceAttr.ConstructorArguments .Select(arg => arg.Value) .ToArray(); // 处理命名参数,映射到特性类的成员 var namedArgs = sourceAttr.NamedArguments .Select(arg => new KeyValuePair<MemberInfo, object>( attrType.GetMember(arg.MemberName).First(), arg.TypedValue.Value)) .ToArray(); // 创建新特性并添加到目标属性 var attrBuilder = new CustomAttributeBuilder(targetCtor, ctorArgs, namedArgs); property.SetCustomAttribute(attrBuilder); }
关键注意事项
- 确保目标模块已引用特性所在的程序集,否则会出现类型或构造函数找不到的错误。
- 对于带复杂参数(如自定义类型、枚举)的特性,要保证目标模块能访问到这些参数的类型,避免加载失败。
- 如果使用特定织入框架(如Fody、PostSharp),可直接用框架提供的跨模块特性复制工具类,这类工具会自动处理模块引用与类型解析问题。
内容的提问来源于stack exchange,提问作者Peter Morris
相关产品推荐
相关产品推荐

