成员在另一个模块中声明,需要导入 [英] Member is declared in another module and needs to be imported

查看:102
本文介绍了成员在另一个模块中声明,需要导入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I use Mono.Cecil to create a new custom attribute type and then add it to an existing type.

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

To demonstrate it, I have a pre-existing DLL called "Sample" with type that is called "SampleType".

我想使用Mono.Cecil在样本中创建一个名为 NewAttribute的新类型,然后将此属性添加到 SampleType中。

I want to use Mono.Cecil to weave in a new type in "Sample" called "NewAttribute" and then add this attribute to "SampleType".

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

The code looks like this: (not exactly but its good enough for example)

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;
}

如您所见,代码中的注释是我尝试修复的尝试问题,但没有成功。
我确定我缺少什么,但我不知道什么。.

As you see, the comments in the code are attempts that I did to fix the problem but without success. I'm sure I'm missing something but I don't know what..

推荐答案

导入方法在Cecil中具有以下签名:

The Import methods in Cecil have the following signature:

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

Import 不管在哪里,都采用类型或方法定义它们,并为它们当前模块创建一个参考。如果不使用它们返回的内容,则您的代码是不正确的。

Import takes a type or a method, no matter where they are defined, and create a reference for them for the current module. If you don't use what they return, your code is not correct.

例如,您编写:

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

在这种情况下,您正在创建 CustomAttribute 用于您的模块,但使用在 mscorlib 中定义的构造函数。相反,您需要在模块中为构造函数创建一个引用,并使用该引用:导入的结果是创建自定义属性时必须使用的结果。

In that case, you're creating a CustomAttribute for your module, but using the constructor defined in mscorlib. You instead need to create a reference for the constructor in your module and use that reference: the result of Import is what you must use when creating the custom attribute.

这篇关于成员在另一个模块中声明,需要导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆