2016-01-19 3 views
5

Mono.Cecilを使用して新しいカスタム属性タイプを作成し、それを既存のタイプに追加します。メンバーは別のモジュールで宣言されており、インポートする必要があります

これを実証するため、「SampleType」と呼ばれるタイプの「Sample」という名前の既存DLLがあります。

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

ご覧の通り、コメントでコードは私が問題を解決するために試みたものですが、成功することはありません。 私は何かが足りないんだと確信しているが、私は何を知らない...次のシグネチャを持つセシルで

答えて

10

のインポート方法:

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

インポート種類や方法をとるが、どんなにそれらが定義されている場所で、現在のモジュールの参照を作成します。彼らが返すものを使用しない場合は、コードが正しくありません。例えば

、あなたが書いた:その場合は

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

を、あなたはmscorlibで定義されたコンストラクタとモジュールのCustomAttributeを作成しています。モジュールのコンストラクタの参照を作成して使用する必要があります。インポートの結果は、カスタム属性を作成するときに使用する必要があります。

私はあなたがインポートのすべての使用を通過し、そのことを確認することをお勧めします

+0

ありがとう!これも私の問題を解決しました。次の文は、「インポートの結果はカスタム属性を作成するときに使用する必要がある」という重要な内容です。 – m1o2

関連する問題