成员在另一个模块中声明,需要导入

我使用Mono.Cecil创建一个新的自定义属性类型,然后将其添加到现有类型。

为了演示它,我有一个名为“Sample”的预先存在的DLL,其类型称为“SampleType”。

我想使用Mono.Cecil在名为“NewAttribute”的“Sample”中编写一个新类型,然后将此属性添加到“SampleType”。

代码看起来像这样:(不完全,但它足够好,例如)

static void AddCustomeAttribute() { var module = ModuleDefinition.ReadModule(AssemblyName); var attrType = NewAttributeProvider.Add(module); var ctor = attrType.GetConstructors().First(); //module.Import(ctor); CustomAttribute attribute = new CustomAttribute(ctor); attribute.ConstructorArguments.Add(new CustomAttributeArgument(module.TypeSystem.String, "InternalClass")); module.CustomAttributes.Add(attribute); module.Write(AssemblyName); //error } 

 public static TypeDefinition Add(ModuleDefinition targetModule) { var type = targetModule.AddType("Namespace", "NewAttribute", TypeAttributes.Public | TypeAttributes.Class, targetModule.Import(typeof(Attribute))); var stringType = targetModule.TypeSystem.String; var nameField = type.AddField(stringType, "_name"); var nameProp = type.AddSimpleProperty(stringType, "Name", nameField); // generate a constructor body var constructor = type.AddConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, targetModule.TypeSystem.Void, new[] { stringType }); constructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); constructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); constructor.Body.Instructions.Add(Instruction.Create(OpCodes.Stfld, nameField)); constructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); var attrUsageType = targetModule.Import(typeof(AttributeUsageAttribute)).Resolve(); //var att = targetModule.Import(typeof(AttributeUsageAttribute)); //targetModule.Import(attrUsageType); var attributeTargetsType = targetModule.Import(typeof(AttributeTargets)); //targetModule.Import(attributeTargetsType); var propertiesToSet = new Dictionary<string, Tuple> { {"AllowMultiple", Tuple.Create(targetModule.TypeSystem.Boolean, (object)true)} }; var usageAttr = type.AddCustomAttribute(attrUsageType, new[] { attributeTargetsType }, propertiesToSet); //targetModule.Import(usageAttr.AttributeType); targetModule.Types.Add(type); return type; } 

 public static CustomAttribute AddCustomAttribute(this TypeDefinition type, TypeDefinition attrType, TypeReference[] ctorParameters, Dictionary<string, Tuple> propetiesToSet) { var attrUsageCtor = attrType.GetConstructors().Single(ctor => ctor.Parameters.Count == ctorParameters.Length && ValidateParameters(ctor.Parameters, ctorParameters)); type.Module.Import(attrUsageCtor); Collection properties = new Collection(); foreach (KeyValuePair<string, Tuple> typeReference in propetiesToSet) { properties.Add(new CustomAttributeNamedArgument(typeReference.Key, new CustomAttributeArgument(typeReference.Value.Item1, typeReference.Value.Item2))); } var customeAttr = new CustomAttribute(attrUsageCtor); foreach (var property in properties) { customeAttr.Properties.Add(property); } type.CustomAttributes.Add(customeAttr); return customeAttr; } 

如您所见,代码中的注释是我尝试解决问题但没有成功的尝试。 我确定我错过了什么,但我不知道是什么……

Cecil中的Import方法具有以下签名:

 TypeReference Import(TypeReference type) MethodReference Import(MethodReference method) 

导入采用类型或方法,无论它们在何处定义,并为当前模块创建它们的引用。 如果您不使用它们返回的内容,则代码不正确。

例如,你写道:

 var attrUsageCtor = attrType.GetConstructors().Single(ctor => ...); type.Module.Import(attrUsageCtor); 

在这种情况下,您将使用mscorlib中定义的构造函数为您创建CustomAttribute模块。 您需要为模块中的构造函数创建一个引用并使用它:Import的结果是您在创建自定义属性时必须使用的结果。

我建议你仔细检查使用Import并validation