成员在另一个模块中声明,需要导入
Member is declared in another module and needs to be imported
我使用 Mono.Cecil 创建新的自定义属性类型,然后将其添加到现有类型。
为了演示它,我有一个名为 "Sample" 的预先存在的 DLL,其类型为 "SampleType"。
我想用Mono.Cecil在"Sample"中编织一个新类型"NewAttribute",然后将这个属性添加到"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<TypeReference, object>>
{
{"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<TypeReference, object>> propetiesToSet)
{
var attrUsageCtor = attrType.GetConstructors().Single(ctor => ctor.Parameters.Count == ctorParameters.Length && ValidateParameters(ctor.Parameters, ctorParameters));
type.Module.Import(attrUsageCtor);
Collection<CustomAttributeNamedArgument> properties = new Collection<CustomAttributeNamedArgument>();
foreach (KeyValuePair<string, Tuple<TypeReference, object>> 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)
Import
采用类型或方法,无论它们在哪里定义,并为它们创建一个引用 当前模块 。如果您不使用它们 return,您的代码不正确。
例如,你写:
var attrUsageCtor = attrType.GetConstructors().Single(ctor => ...);
type.Module.Import(attrUsageCtor);
在这种情况下,您正在为您的模块创建一个 CustomAttribute
,但使用 mscorlib
中定义的构造函数。相反,您需要为模块中的构造函数创建一个引用并使用该引用:Import
的结果是您在创建自定义属性时必须使用的结果。
我使用 Mono.Cecil 创建新的自定义属性类型,然后将其添加到现有类型。
为了演示它,我有一个名为 "Sample" 的预先存在的 DLL,其类型为 "SampleType"。
我想用Mono.Cecil在"Sample"中编织一个新类型"NewAttribute",然后将这个属性添加到"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<TypeReference, object>>
{
{"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<TypeReference, object>> propetiesToSet)
{
var attrUsageCtor = attrType.GetConstructors().Single(ctor => ctor.Parameters.Count == ctorParameters.Length && ValidateParameters(ctor.Parameters, ctorParameters));
type.Module.Import(attrUsageCtor);
Collection<CustomAttributeNamedArgument> properties = new Collection<CustomAttributeNamedArgument>();
foreach (KeyValuePair<string, Tuple<TypeReference, object>> 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)
Import
采用类型或方法,无论它们在哪里定义,并为它们创建一个引用 当前模块 。如果您不使用它们 return,您的代码不正确。
例如,你写:
var attrUsageCtor = attrType.GetConstructors().Single(ctor => ...);
type.Module.Import(attrUsageCtor);
在这种情况下,您正在为您的模块创建一个 CustomAttribute
,但使用 mscorlib
中定义的构造函数。相反,您需要为模块中的构造函数创建一个引用并使用该引用:Import
的结果是您在创建自定义属性时必须使用的结果。