2016-01-19 3 views
5

Я использую Mono.Cecil для создания нового настраиваемого типа атрибута, а затем добавьте его в существующий тип.Участник объявляется в другом модуле и должен быть импортирован

Чтобы продемонстрировать это, у меня есть уже существующая 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; 
} 

Как вы видите, комментарии в код - это попытки, которые я сделал для устранения проблемы, но безуспешно. Я уверен, что я что-то отсутствует, но я не знаю, что ..

ответ

10

Методы Импорт в Cecil имеют следующую подпись:

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

Импорт принимает тип или метод, независимо от того, где они определены, и создать для них ссылку для текущего модуля. Если вы не используете то, что они вернут, ваш код неверен.

Например, вы пишете:

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

В этом случае, вы создаете CustomAttribute для вас модуль с конструктором, определенным в mscorlib. Вам нужно создать ссылку для конструктора в вашем модуле и использовать его: результат импорта - это то, что вы должны использовать при создании настраиваемого атрибута.

Я предлагаю вам пройти через все использование Импорта и подтвердить, что

+0

Спасибо! Это также решило мою проблему. Следующее предложение - это то, что важно «результат импорта - это то, что вы должны использовать при создании настраиваемого атрибута». – m1o2

Смежные вопросы