it-swarm.com.de

Reflection - Ermittelt den Attributnamen und den Wert der Eigenschaft

Ich habe eine Klasse, nennen wir es Book mit einer Eigenschaft namens Name. Mit dieser Eigenschaft habe ich ein Attribut zugeordnet.

public class Book
{
    [Author("AuthorName")]
    public string Name
    {
        get; private set; 
    }
}

In meiner Hauptmethode verwende ich Reflection und möchte für jede Eigenschaft ein Schlüsselwertpaar jedes Attributs erhalten. In diesem Beispiel würde ich also erwarten, dass "Author" für den Attributnamen und "AuthorName" für den Attributwert angezeigt wird.

Frage: Wie erhalte ich mit Reflection den Attributnamen und den Wert meiner Eigenschaften?

189
developerdoug

Verwenden Sie typeof(Book).GetProperties(), um ein Array von PropertyInfo-Instanzen abzurufen. Verwenden Sie dann GetCustomAttribute() für jede PropertyInfo, um zu sehen, ob einer von ihnen den Attributstyp Author hat. Wenn dies der Fall ist, können Sie den Namen der Eigenschaft aus der Eigenschaftsinfo und die Attributwerte aus dem Attribut erhalten.

Etwas in dieser Richtung, um einen Typ nach Eigenschaften zu durchsuchen, die einen bestimmten Attributtyp haben, und um Daten in einem Wörterbuch zurückzugeben (beachten Sie, dass dies dynamischer werden kann, indem Sie Typen in die Routine übergeben):

public static Dictionary<string, string> GetAuthors()
{
    Dictionary<string, string> _dict = new Dictionary<string, string>();

    PropertyInfo[] props = typeof(Book).GetProperties();
    foreach (PropertyInfo prop in props)
    {
        object[] attrs = prop.GetCustomAttributes(true);
        foreach (object attr in attrs)
        {
            AuthorAttribute authAttr = attr as AuthorAttribute;
            if (authAttr != null)
            {
                string propName = prop.Name;
                string auth = authAttr.Name;

                _dict.Add(propName, auth);
            }
        }
    }

    return _dict;
}
232
Adam Markowitz

Um alle Attribute einer Eigenschaft in einem Wörterbuch abzurufen, verwenden Sie Folgendes:

typeof(Book)
  .GetProperty("Name")
  .GetCustomAttributes(false)
  .ToDictionary(a => a.GetType().Name, a => a);

denken Sie daran, von false in true zu ändern, wenn Sie auch geerbte Attribute einschließen möchten.

90
Mo Valipour

Wenn Sie nur einen bestimmten Attributwert wünschen Zum Beispiel Attribut anzeigen können Sie folgenden Code verwenden:

var pInfo = typeof(Book).GetProperty("Name")
                             .GetCustomAttribute<DisplayAttribute>();
var name = pInfo.Name;
35
maxspan

Sie können GetCustomAttributesData() und GetCustomAttributes() verwenden:

var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData();
var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);
19
BrokenGlass

Ich habe ähnliche Probleme gelöst, indem ich einen Attribut-Helper für generische Erweiterungen schrieb:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public static class AttributeHelper
{
    public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(
        Expression<Func<T, TOut>> propertyExpression, 
        Func<TAttribute, TValue> valueSelector) 
        where TAttribute : Attribute
    {
        var expression = (MemberExpression) propertyExpression.Body;
        var propertyInfo = (PropertyInfo) expression.Member;
        var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() as TAttribute;
        return attr != null ? valueSelector(attr) : default(TValue);
    }
}

Verwendungszweck:

var author = AttributeHelper.GetPropertyAttributeValue<Book, string, AuthorAttribute, string>(prop => prop.Name, attr => attr.Author);
// author = "AuthorName"
17
Mikael Engver

Wenn Sie "für Attribute, die einen Parameter benötigen, die Attributnamen und den Parameterwert auflisten" meinen, dann ist dies in .NET 4.5 über die CustomAttributeData-API einfacher:

using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

public static class Program
{
    static void Main()
    {
        PropertyInfo prop = typeof(Foo).GetProperty("Bar");
        var vals = GetPropertyAttributes(prop);
        // has: DisplayName = "abc", Browsable = false
    }
    public static Dictionary<string, object> GetPropertyAttributes(PropertyInfo property)
    {
        Dictionary<string, object> attribs = new Dictionary<string, object>();
        // look for attributes that takes one constructor argument
        foreach (CustomAttributeData attribData in property.GetCustomAttributesData()) 
        {

            if(attribData.ConstructorArguments.Count == 1)
            {
                string typeName = attribData.Constructor.DeclaringType.Name;
                if (typeName.EndsWith("Attribute")) typeName = typeName.Substring(0, typeName.Length - 9);
                attribs[typeName] = attribData.ConstructorArguments[0].Value;
            }

        }
        return attribs;
    }
}

class Foo
{
    [DisplayName("abc")]
    [Browsable(false)]
    public string Bar { get; set; }
}
12
Marc Gravell
private static Dictionary<string, string> GetAuthors()
{
    return typeof(Book).GetProperties()
        .SelectMany(prop => prop.GetCustomAttributes())
        .OfType<AuthorAttribute>()
        .ToDictionary(attribute => attribute.Name, attribute => attribute.Name);
}
3
dee

Nekromanzierung. 
Für diejenigen, die .NET 2.0 noch pflegen müssen oder dies ohne LINQ tun möchten:

public static object GetAttribute(System.Reflection.MemberInfo mi, System.Type t)
{
    object[] objs = mi.GetCustomAttributes(t, true);

    if (objs == null || objs.Length < 1)
        return null;

    return objs[0];
}



public static T GetAttribute<T>(System.Reflection.MemberInfo mi)
{
    return (T)GetAttribute(mi, typeof(T));
}


public delegate TResult GetValue_t<in T, out TResult>(T arg1);

public static TValue GetAttributValue<TAttribute, TValue>(System.Reflection.MemberInfo mi, GetValue_t<TAttribute, TValue> value) where TAttribute : System.Attribute
{
    TAttribute[] objAtts = (TAttribute[])mi.GetCustomAttributes(typeof(TAttribute), true);
    TAttribute att = (objAtts == null || objAtts.Length < 1) ? default(TAttribute) : objAtts[0];
    // TAttribute att = (TAttribute)GetAttribute(mi, typeof(TAttribute));

    if (att != null)
    {
        return value(att);
    }
    return default(TValue);
}

Verwendungsbeispiel:

System.Reflection.FieldInfo fi = t.GetField("PrintBackground");
wkHtmlOptionNameAttribute att = GetAttribute<wkHtmlOptionNameAttribute>(fi);
string name = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, delegate(wkHtmlOptionNameAttribute a){ return a.Name;});

oder einfach 

string aname = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, a => a.Name );
2
Stefan Steiger
public static class PropertyInfoExtensions
{
    public static TValue GetAttributValue<TAttribute, TValue>(this PropertyInfo prop, Func<TAttribute, TValue> value) where TAttribute : Attribute
    {
        var att = prop.GetCustomAttributes(
            typeof(TAttribute), true
            ).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return value(att);
        }
        return default(TValue);
    }
}

Verwendungszweck:

 //get class properties with attribute [AuthorAttribute]
        var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute)));
            foreach (var prop in props)
            {
               string value = prop.GetAttributValue((AuthorAttribute a) => a.Name);
            }

oder:

 //get class properties with attribute [AuthorAttribute]
        var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute)));
        IList<string> values = props.Select(prop => prop.GetAttributValue((AuthorAttribute a) => a.Name)).Where(attr => attr != null).ToList();
1
Victor

Suchen Sie einfach nach dem richtigen Ort, um diesen Code zu platzieren.

angenommen, Sie haben die folgende Eigenschaft:

[Display(Name = "Solar Radiation (Average)", ShortName = "SolarRadiationAvg")]
public int SolarRadiationAvgSensorId { get; set; }

Und Sie möchten den ShortName-Wert abrufen. Du kannst tun:

((DisplayAttribute)(typeof(SensorsModel).GetProperty(SolarRadiationAvgSensorId).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;

Oder um es allgemein zu machen:

internal static string GetPropertyAttributeShortName(string propertyName)
{
    return ((DisplayAttribute)(typeof(SensorsModel).GetProperty(propertyName).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;
}
0
Asaf

um das Attribut von enum zu erhalten, verwende ich:

 public enum ExceptionCodes
 {
  [ExceptionCode(1000)]
  InternalError,
 }

 public static (int code, string message) Translate(ExceptionCodes code)
        {
            return code.GetType()
            .GetField(Enum.GetName(typeof(ExceptionCodes), code))
            .GetCustomAttributes(false).Where((attr) =>
            {
                return (attr is ExceptionCodeAttribute);
            }).Select(customAttr =>
            {
                var attr = (customAttr as ExceptionCodeAttribute);
                return (attr.Code, attr.FriendlyMessage);
            }).FirstOrDefault();
        }

// Verwendung

 var _message = Translate(code);
0
Mohamed.Abdo

Obwohl die oben genannten Antworten mit Sicherheit am besten funktionieren, würde ich in einigen Fällen einen etwas anderen Ansatz vorschlagen.

Wenn Ihre Klasse mehrere Eigenschaften mit immer demselben Attribut hat und Sie diese Attribute in einem Wörterbuch sortieren möchten, gehen Sie wie folgt vor:

var dict = typeof(Book).GetProperties().ToDictionary(p => p.Name, p => p.GetCustomAttributes(typeof(AuthorName), false).Select(a => (AuthorName)a).FirstOrDefault());

Dies verwendet weiterhin die Umwandlung, stellt jedoch sicher, dass die Umwandlung immer funktioniert, da Sie nur die benutzerdefinierten Attribute des Typs "AuthorName" erhalten. Wenn Sie mehrere Attribute über den Antworten hatten, würde dies zu einer Cast-Ausnahme führen.

0
Mirko Brandt
foreach (var p in model.GetType().GetProperties())
{
   var valueOfDisplay = 
       p.GetCustomAttributesData()
        .Any(a => a.AttributeType.Name == "DisplayNameAttribute") ? 
            p.GetCustomAttribute<DisplayNameAttribute>().DisplayName : 
            p.Name;
}

In diesem Beispiel habe ich DisplayName anstelle von Author verwendet, da dort ein Feld mit dem Namen 'DisplayName' mit einem Wert angezeigt wird.

0
petrosmm

Hier sind einige statische Methoden, die Sie verwenden können, um die MaxLength oder ein beliebiges anderes Attribut abzurufen.

using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;

public static class AttributeHelpers {

public static Int32 GetMaxLength<T>(Expression<Func<T,string>> propertyExpression) {
    return GetPropertyAttributeValue<T,string,MaxLengthAttribute,Int32>(propertyExpression,attr => attr.Length);
}

//Optional Extension method
public static Int32 GetMaxLength<T>(this T instance,Expression<Func<T,string>> propertyExpression) {
    return GetMaxLength<T>(propertyExpression);
}


//Required generic method to get any property attribute from any class
public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(Expression<Func<T,TOut>> propertyExpression,Func<TAttribute,TValue> valueSelector) where TAttribute : Attribute {
    var expression = (MemberExpression)propertyExpression.Body;
    var propertyInfo = (PropertyInfo)expression.Member;
    var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute),true).FirstOrDefault() as TAttribute;

    if (attr==null) {
        throw new MissingMemberException(typeof(T).Name+"."+propertyInfo.Name,typeof(TAttribute).Name);
    }

    return valueSelector(attr);
}

}

Mit der statischen Methode ...

var length = AttributeHelpers.GetMaxLength<Player>(x => x.PlayerName);

Oder verwenden Sie die optionale Erweiterungsmethode für eine Instanz ...

var player = new Player();
var length = player.GetMaxLength(x => x.PlayerName);

Oder verwenden Sie die vollständige statische Methode für jedes andere Attribut (z. B. StringLength) ...

var length = AttributeHelpers.GetPropertyAttributeValue<Player,string,StringLengthAttribute,Int32>(prop => prop.PlayerName,attr => attr.MaximumLength);

Inspiriert von der Antwort von Mikael Engver.

0
Carter Medlin