2016-01-19 19 views
5

Ich verwende Mono.Cecil, um einen neuen benutzerdefinierten Attributtyp zu erstellen und ihn dann einem vorhandenen Typ hinzuzufügen.Mitglied wird in einem anderen Modul deklariert und muss importiert werden

Um es zu demonstrieren, habe ich eine bereits vorhandene DLL namens "Sample" mit Typ, der "SampleType" genannt wird.

Ich möchte Mono.Cecil verwenden, um einen neuen Typ in "Sample" namens "NewAttribute" zu weben und dann dieses Attribut zu "SampleType" hinzuzufügen.

Der Code sieht wie folgt aus: (nicht genau aber es ist gut genug, um zum Beispiel)

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

Wie Sie sehen, die Kommentare in Der Code sind Versuche, die ich getan habe, um das Problem zu beheben, aber ohne Erfolg. Ich bin sicher, dass ich etwas fehlt, aber ich weiß nicht, was ..

Antwort

10

Die Import-Methoden in Cecil haben die folgende Signatur:

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

Import einen Typ oder eine Methode verwendet, ganz gleich, wo sie definiert sind, und erstellen Sie eine Referenz für sie für das aktuelle Modul. Wenn Sie das, was sie zurückgeben, nicht verwenden, ist Ihr Code nicht korrekt.

Zum Beispiel schreiben Sie:

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

In diesem Fall, erstellen Sie eine CustomAttribute für Sie mit dem Konstruktor Modul in mscorlib definiert. Sie müssen einen Verweis für den Konstruktor in Ihrem Modul erstellen und verwenden: Das Ergebnis von Import müssen Sie beim Erstellen des benutzerdefinierten Attributs verwenden.

Ich schlage vor, Sie gehen durch die Verwendung von Import und überprüfen, dass

+0

Vielen Dank! Das hat mein Problem auch gelöst. Der folgende Satz ist wichtig "das Ergebnis von Import ist das, was Sie verwenden müssen, wenn Sie das benutzerdefinierte Attribut erstellen". – m1o2