2010-03-02 4 views
4

Je tente de générer un nouvel ensemble d'interfaces wcf basé sur des interfaces existantes. J'utilise l'espace de noms Reflection.Emit pour accomplir ceci. Mon problème est de savoir comment copier les anciens attributs personnalisés d'une méthode à la nouvelle méthode. Chaque exemple que j'ai vu de SetCustomAttributes() nécessite de connaître au préalable le type d'attribut. J'ai besoin de découvrir le type d'attribut lors de l'exécution. Des pensées?Utilisation de Reflection.Emit pour copier un attribut personnalisé dans une autre méthode

Répondre

0

essayez ceci:

MethodInfo mi; 
//... 
object[] custAttribs = mi.GetCustomAttributes(false); 
foreach (object attrib in custAttribs) 
    attrib.GetType(); 

Je suppose que vous avez MethodInfo pour vos méthodes

2

Voici la réponse que je suis venu avec après quelques recherches.

CustomAttributeBuilder ct = AddAttributesToMemberInfo(methodInfo); 
if (ct != null) 
{ 
    methodBuilder.SetCustomAttribute(ct); 
} 

CustomAttributeBuilder AddAttributesToMemberInfo(MemberInfo oldMember) 
{ 
    CustomAttributeBuilder ct = null; 
    IList<CustomAttributeData> customMethodAttributes = CustomAttributeData.GetCustomAttributes(oldMember); 
    foreach (CustomAttributeData att in customMethodAttributes) 
    { 
     List<object> namedFieldValues = new List<object>(); 
     List<FieldInfo> fields = new List<FieldInfo>(); 
     List<object> constructorArguments = new List<object>(); 
     foreach (CustomAttributeTypedArgument cata in att.ConstructorArguments) 
     { 
      constructorArguments.Add(cata.Value); 
     } 
     if (att.NamedArguments.Count > 0) 
     { 
      FieldInfo[] possibleFields = att.GetType().GetFields(); 

      foreach (CustomAttributeNamedArgument cana in att.NamedArguments) 
      { 
       for (int x = 0; x < possibleFields.Length; x++) 
       { 
        if (possibleFields[x].Name.CompareTo(cana.MemberInfo.Name) == 0) 
        { 
         fields.Add(possibleFields[x]); 
         namedFieldValues.Add(cana.TypedValue.Value); 
        } 
       } 


      } 
     } 

     if (namedFieldValues.Count > 0) 
     { 
      ct = new CustomAttributeBuilder(att.Constructor, constructorArguments.ToArray(), fields.ToArray(), namedFieldValues.ToArray()); 
     } 
     else 
     { 
      ct = new CustomAttributeBuilder(att.Constructor, constructorArguments.ToArray()); 
     } 


    } 
    return ct; 
} 
5

La réponse que vous (frjames) est proche au courant, mais ne tient pas compte initializers de propriété comme ...

[ServiceBehavior(Name="ServiceName")] 

Cependant, l'idée de convertir CustomAttributeData à un CustomAttributeBuilder pour une utilisation dans la réflexion .Emit est juste sur.

J'ai fini par le faire pour un projet open source (Autofac) et est venu avec cette méthode d'extension:

public static CustomAttributeBuilder ToAttributeBuilder(this CustomAttributeData data) 
{ 
    if (data == null) 
    { 
    throw new ArgumentNullException("data"); 
    } 

    var constructorArguments = new List<object>(); 
    foreach (var ctorArg in data.ConstructorArguments) 
    { 
    constructorArguments.Add(ctorArg.Value); 
    } 

    var propertyArguments = new List<PropertyInfo>(); 
    var propertyArgumentValues = new List<object>(); 
    var fieldArguments = new List<FieldInfo>(); 
    var fieldArgumentValues = new List<object>(); 
    foreach (var namedArg in data.NamedArguments) 
    { 
    var fi = namedArg.MemberInfo as FieldInfo; 
    var pi = namedArg.MemberInfo as PropertyInfo; 

    if (fi != null) 
    { 
     fieldArguments.Add(fi); 
     fieldArgumentValues.Add(namedArg.TypedValue.Value); 
    } 
    else if (pi != null) 
    { 
     propertyArguments.Add(pi); 
     propertyArgumentValues.Add(namedArg.TypedValue.Value); 
    } 
    } 
    return new CustomAttributeBuilder(
    data.Constructor, 
    constructorArguments.ToArray(), 
    propertyArguments.ToArray(), 
    propertyArgumentValues.ToArray(), 
    fieldArguments.ToArray(), 
    fieldArgumentValues.ToArray()); 
} 

Que l'on tient compte de toutes les façons d'initialiser l'attribut.

+0

Je sais que c'est vieux, mais cela est une excellente réponse et m'a sauvé un tas de temps récemment mais je n'ai rencontré un petit problème avec cela aussi. Si vous avez un attribut qui a un argument 'params SomeType [] constructor' (je ne suis pas sûr si les params font une différence ou pas) alors cela échoue parce que pour une raison quelconque la valeur de l'argument constructeur est maintenue comme ReadOnlyCollection ' qui ne peut pas être converti en 'SomeType []' par le constructeur CustomAttributeBuilder. – rcarrington

+0

Ne fonctionne pas dans .Net Core ''CustomAttributeNamedArgument' ne contient pas de définition pour 'MemberInfo'' –

+0

La question/réponse ici a six ans maintenant et est pour le .NET complet. La réflexion du noyau .NET est très différente. –

1

Le code de Travis Illig doit être modifié comme ci-dessous pour travailler avec .Net de base:

foreach (var namedArg in data.NamedArguments) 
{ 
    string argName = namedArg.MemberName; 
    var fi = data.AttributeType.GetField(argName); 
    var pi = data.AttributeType.GetProperty(argName); 
Questions connexes