Ruft den Wert des DisplayName-Attributs ab

75
public class Class1
{
    [DisplayName("Something To Name")]
    public virtual string Name { get; set; }
}

Wie erhalte ich den Wert des DisplayName-Attributs in C #?

Bassam Bsata
quelle

Antworten:

84

Probieren Sie meine Dienstprogrammmethoden aus:

using System.ComponentModel;
using System.Globalization;
using System.Linq;


public static T GetAttribute<T>(this MemberInfo member, bool isRequired)
    where T : Attribute
{
    var attribute = member.GetCustomAttributes(typeof(T), false).SingleOrDefault();

    if (attribute == null && isRequired)
    {
        throw new ArgumentException(
            string.Format(
                CultureInfo.InvariantCulture, 
                "The {0} attribute must be defined on member {1}", 
                typeof(T).Name, 
                member.Name));
    }

    return (T)attribute;
}

public static string GetPropertyDisplayName<T>(Expression<Func<T, object>> propertyExpression)
{
    var memberInfo = GetPropertyInformation(propertyExpression.Body);
    if (memberInfo == null)
    {
        throw new ArgumentException(
            "No property reference expression was found.",
            "propertyExpression");
    }

    var attr = memberInfo.GetAttribute<DisplayNameAttribute>(false);
    if (attr == null)
    {
        return memberInfo.Name;
    }

    return attr.DisplayName;
}

public static MemberInfo GetPropertyInformation(Expression propertyExpression)
{
    Debug.Assert(propertyExpression != null, "propertyExpression != null");
    MemberExpression memberExpr = propertyExpression as MemberExpression;
    if (memberExpr == null)
    {
        UnaryExpression unaryExpr = propertyExpression as UnaryExpression;
        if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Convert)
        {
            memberExpr = unaryExpr.Operand as MemberExpression;
        }
    }

    if (memberExpr != null && memberExpr.Member.MemberType == MemberTypes.Property)
    {
        return memberExpr.Member;
    }

    return null;
}

Verwendung wäre:

string displayName = ReflectionExtensions.GetPropertyDisplayName<SomeClass>(i => i.SomeProperty);
Rich Tebb
quelle
Könnten Sie mir bitte helfen, den richtigen Weg zu finden, um alle Eigenschaften von DisplayName zu durchlaufen? stackoverflow.com/questions/12868901/…
DmitryBoyko
1
@ rich-tebb Es scheint, dass dies nicht funktioniert, wenn Sie [Display (Name = "SomeProperty", ResourceType = typeof (SomeResource))] haben. Es gibt keinen lokalisierten Namen zurück. Ich werde versuchen, es so zu ändern, dass es funktioniert.
Matija Grcic
Ein kleines Code-Snippet zum Lesen des lokalisierten Werts aus DisplayAttribute wurde hinzugefügt.
Matija Grcic
1
public static T GetAttribute <T> (diese Erweiterungsmethode kann nicht in einer nicht generischen, nicht verschachtelten statischen Klasse deklariert werden
MIKE
public static ThankYou
Ashraf Abusada
34

Zunächst müssen Sie ein MemberInfoObjekt abrufen, das diese Eigenschaft darstellt. Sie müssen irgendeine Form der Reflexion machen:

MemberInfo property = typeof(Class1).GetProperty("Name");

(Ich verwende die Reflexion im "alten Stil", aber Sie können auch einen Ausdrucksbaum verwenden, wenn Sie zur Kompilierungszeit Zugriff auf den Typ haben.)

Dann können Sie das Attribut abrufen und den Wert der DisplayNameEigenschaft erhalten:

var attribute = property.GetCustomAttributes(typeof(DisplayNameAttribute), true)
      .Cast<DisplayNameAttribute>().Single();
string displayName = attribute.DisplayName;

() Klammern sind Tippfehler erforderlich

R. Martinho Fernandes
quelle
4
Wenn displayNameAttribute null ist, schlägt dies fehl. Anstatt nur einen einzigen Versuch zurückzugeben, versuchen Sie, FirstOrDefault () zurückzugeben, und prüfen Sie dann, ob dieser Wert null ist oder nicht.
Rkmorgan
31

Sie müssen die PropertyInfomit der Eigenschaft verknüpfte (z. B. via typeof(Class1).GetProperty("Name")) abrufen und dann anrufen GetCustomAttributes.

Es ist etwas chaotisch, weil mehrere Werte zurückgegeben werden. Möglicherweise möchten Sie eine Hilfsmethode schreiben, um dies zu tun, wenn Sie sie an einigen Stellen benötigen. (Möglicherweise gibt es bereits irgendwo eine Hilfsmethode im Framework, aber wenn ja, weiß ich nichts davon.)

EDIT: Wie Leppie betonte, gibt es eine solche Methode:Attribute.GetCustomAttribute(MemberInfo, Type)

Jon Skeet
quelle
18
Wir haben Attribute.GetCustomAttribute(MemberInfo, Type) :) msdn.microsoft.com/en-us/library/ms130863
Leppie
1
@ leppie: Oh, schön. Ich bin mir nicht sicher, warum ich das nie entdeckt hatte.
Jon Skeet
1
@cesAR: Sie haben einen Link zurück zu dieser Frage gepostet . Aber bitte tun Sie dies im Allgemeinen nicht - es ist fast nie angebracht, Kommentare zu einer Antwort zu hinterlassen, die auf eine andere Frage verweist.
Jon Skeet
12

In einer Ansicht mit Class1 als stark typisiertem Ansichtsmodell:

ModelMetadata.FromLambdaExpression<Class1, string>(x => x.Name, ViewData).DisplayName;
Luke Bennett
quelle
Ich denke, dies sollte die akzeptierte Antwort sein ... Ich gehe davon aus, dass es klug genug ist, die zwischengespeicherten Metadatenobjekte intern zu verwenden. so oder so, nett und prägnant und mit .nets eigenen Methoden
The Bearded Llama
Nur über System.Web.Mvc verfügbar - nicht jeder macht Web-Apps, auch im Jahr 2020.
Yoda
12

Wenn jemand daran interessiert ist, die lokalisierte Zeichenfolge mit DisplayAttribute und ResourceType wie folgt aus der Eigenschaft abzurufen :

[Display(Name = "Year", ResourceType = typeof(ArrivalsResource))]
public int Year { get; set; }

Verwenden Sie nachfolgend Folgendes displayAttribute != null(wie oben in der Antwort von @alex gezeigt ):

ResourceManager resourceManager = new ResourceManager(displayAttribute.ResourceType);
var entry = resourceManager.GetResourceSet(Thread.CurrentThread.CurrentUICulture, true, true)
                           .OfType<DictionaryEntry>()
                           .FirstOrDefault(p => p.Key.ToString() == displayAttribute.Name);

return entry.Value.ToString();
Matija Grcic
quelle
6
DisplayAttributehat GetNameMethode. Ihr Code in .NET 4+ ist nicht erforderlich
Salar
1
@Salar Während Sie korrekt sind, werden Sie leicht irregeführt. Wenn ein Ressourcentyp angegeben wird, gibt die GetName()Methode nur den Schlüssel und nicht den in der Ressourcendatei angegebenen Wert zurück.
Matt Griffiths
@MattGriffiths Was ist diese Variable ' displayAttribute '?
Dark_Knight
@Dark_Knight Dies ist wahrscheinlich die Variable, die das Ergebnis dieser Anzeigeattributabfrage enthält. Ein Beispiel hierfür finden Sie unter stackoverflow.com/a/10048758/3941350 .
Yoda
Wie von Salar hervorgehoben, ist es besser, .GetName()anstelle des obigen Codes zu verwenden, siehe das Problem, das ich mit dem obigen Code hier hatte: stackoverflow.com/questions/43827360/…
JP Tétreault
9

Schöne Klassen von Rich Tebb! Ich habe DisplayAttribute verwendet und der Code hat bei mir nicht funktioniert. Das einzige, was ich hinzugefügt habe, ist die Handhabung von DisplayAttribute. Eine kurze Suche ergab, dass dieses Attribut für MVC3 & .Net 4 neu ist und fast dasselbe und noch mehr bewirkt. Hier ist eine modifizierte Version der Methode:

 public static string GetPropertyDisplayString<T>(Expression<Func<T, object>> propertyExpression)
    {
        var memberInfo = GetPropertyInformation(propertyExpression.Body);
        if (memberInfo == null)
        {
            throw new ArgumentException(
                "No property reference expression was found.",
                "propertyExpression");
        }

        var displayAttribute = memberInfo.GetAttribute<DisplayAttribute>(false);

        if (displayAttribute != null)
        {
            return displayAttribute.Name;
        }
        else
        {
            var displayNameAttribute = memberInfo.GetAttribute<DisplayNameAttribute>(false);
            if (displayNameAttribute != null)
            {
                return displayNameAttribute.DisplayName;
            }
            else
            {
                return memberInfo.Name;
            }
        }
    }
Alex
quelle
8
var propInfo = typeof(Class1).GetProperty("Name");
var displayNameAttribute = propInfo.GetCustomAttributes(typeof(DisplayNameAttribute), false);
var displayName = (displayNameAttribute[0] as DisplayNameAttribute).DisplayName;

displayName Variable enthält jetzt den Wert der Eigenschaft.

Dishan Samarawickrama
quelle
1
Das sieht so hackig aus
Kolob Canyon
4

Ich habe diese generische Dienstprogrammmethode. Ich übergebe eine Liste eines bestimmten Typs (vorausgesetzt, Sie haben eine unterstützende Klasse) und sie generiert eine Datentabelle mit den Eigenschaften als Spaltenüberschriften und den Listenelementen als Daten.

Wenn Sie wie in Standard-MVC kein DisplayName-Attribut definiert haben, wird auf den Eigenschaftsnamen zurückgegriffen, sodass Sie DisplayName nur dort einfügen müssen, wo es sich vom Eigenschaftsnamen unterscheidet.

    public DataTable BuildDataTable<T>(IList<T> data)
    {
        //Get properties
        PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        //.Where(p => !p.GetGetMethod().IsVirtual && !p.GetGetMethod().IsFinal).ToArray(); //Hides virtual properties

        //Get column headers
        bool isDisplayNameAttributeDefined = false;
        string[] headers = new string[Props.Length];
        int colCount = 0;
        foreach (PropertyInfo prop in Props)
        {
            isDisplayNameAttributeDefined = Attribute.IsDefined(prop, typeof(DisplayNameAttribute));

            if (isDisplayNameAttributeDefined)
            {
                DisplayNameAttribute dna = (DisplayNameAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayNameAttribute));
                if (dna != null)
                    headers[colCount] = dna.DisplayName;
            }
            else
                headers[colCount] = prop.Name;

            colCount++;
            isDisplayNameAttributeDefined = false;
        }

        DataTable dataTable = new DataTable(typeof(T).Name);

        //Add column headers to datatable
        foreach (var header in headers)
            dataTable.Columns.Add(header);

        dataTable.Rows.Add(headers);

        //Add datalist to datatable
        foreach (T item in data)
        {
            object[] values = new object[Props.Length];
            for (int col = 0; col < Props.Length; col++)
                values[col] = Props[col].GetValue(item, null);

            dataTable.Rows.Add(values);
        }

        return dataTable;
    }

Wenn es einen effizienteren / sichereren Weg gibt, würde ich jedes Feedback begrüßen. Die kommentierte // Where-Klausel filtert virtuelle Eigenschaften heraus. Nützlich, wenn Sie Modellklassen direkt verwenden, da EF die Eigenschaften "Navigation" als virtuell einfügt. Es werden jedoch auch Ihre eigenen virtuellen Eigenschaften herausgefiltert, wenn Sie solche Klassen erweitern. Aus diesem Grund ziehe ich es vor, ein ViewModel zu erstellen und es nach Bedarf nur mit den erforderlichen Eigenschaften und Anzeigenamenattributen zu dekorieren und dann eine Liste davon zu erstellen.

Hoffe das hilft.

Francis Rodgers
quelle
3
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(foo);

foreach (PropertyDescriptor property in properties)
{
    if (property.Name == "Name")
    {
        Console.WriteLine(property.DisplayName); // Something To Name
    }
}

Wo fooist eine Instanz vonClass1

Foo
quelle
2

Spät zur Party, die ich kenne.

Ich benutze das:

public static string GetPropertyDisplayName(PropertyInfo pi)
{
  var dp = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault();
  return dp != null ? dp.DisplayName : pi.Name;
}

Hoffe das hilft.

Raul Marquez
quelle
1

Angenommen, propertyals PropertyInfoTyp können Sie dies in einer einzigen Zeile tun:

property.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().Single().DisplayName
Leonel Sanches da Silva
quelle
1

Versuchen Sie diesen Code:

EnumEntity.item.GetType().GetFields()[(int)EnumEntity.item].CustomAttributes.ToArray()[0].NamedArguments[0].TypedValue.ToString()

Sie erhalten den Wert des Datenattributs Name.

Rafael
quelle
0

Bitte versuchen Sie es mit dem folgenden Code. Ich denke, dies wird Ihr Problem lösen.

var classObj = new Class1();
classObj.Name => "StackOverflow";

var property = new Class1().GetType().GetProperty(nameof(classObj.Name));
var displayNameAttributeValue = (property ?? throw new InvalidOperationException())
    .GetCustomAttributes(typeof(DisplayNameAttribute)) as DisplayNameAttribute; 

if (displayNameAttributeValue != null)
{
   Console.WriteLine("{0} = {1}", displayNameAttributeValue, classObj.Name);
}
Sid
quelle
Bitte fügen Sie einige Erklärungen / Inline-Code-Kommentare hinzu, um zu erklären, wie Ihr Code funktioniert und die OP-Abfrage löst.
Madhur Bhaiya
0

Nach der Antwort von Rich Tebb und Matt Baker wollte ich die ReflectionExtensionsMethoden in einer LINQ-Abfrage verwenden, aber es hat nicht funktioniert, also habe ich diese Methode so gemacht, dass sie funktioniert.

Wenn DisplayNameAttributefestgelegt, gibt die Methode es zurück, andernfalls wird der MemberInfoName zurückgegeben.

Testmethode:

static void Main(string[] args)
{
    var lst = new List<Test>();
    lst.Add(new Test("coucou1", "kiki1"));
    lst.Add(new Test("coucou2", "kiki2"));
    lst.Add(new Test("coucou3", "kiki3"));
    lst.Add(new Test("coucou4", "kiki4"));
    lst.ForEach(i => 
        Console.WriteLine(i.GetAttributeName<Test>(t => t.Name) + ";" + i.GetAttributeName<Test>(t=>t.t2)));
}

Ausgabe der Testmethode:

Ausgabe der Testmethode

Die Klasse mit DisplayName1Attribut:

public class Test
{
    public Test() { }
    public Test(string name, string T2)
    {
        Name = name;
        t2 = T2;
    }
    [DisplayName("toto")]
    public string Name { get; set; }
    public string t2 { get; set; }
}

Und die Erweiterungsmethode:

public static string GetAttributeName<T>(this T itm, Expression<Func<T, object>> propertyExpression)
{
    var memberInfo = GetPropertyInformation(propertyExpression.Body);
    if (memberInfo == null)
    {
        throw new ArgumentException(
            "No property reference expression was found.",
            "propertyExpression");
    }

    var pi = typeof(T).GetProperty(memberInfo.Name);
    var ret = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault();
    return ret != null ? ret.DisplayName : pi.Name;

}}

Xavave
quelle
GetPropertyInformation()existiert in diesem Zusammenhang nicht. Ich habe gerade festgestellt, dass dieser Code in einer Antwort unten vorhanden ist
Klicker
0

Wenn stattdessen

[DisplayName ("Etwas zu benennen")]

Sie verwenden

[Anzeige (Name = "Etwas zu benennen")]

Mach das einfach:

private string GetDisplayName(Class1 class1)
{
    string displayName = string.Empty;

    string propertyName = class1.Name.GetType().Name;

    CustomAttributeData displayAttribute = class1.GetType().GetProperty(propertyName).CustomAttributes.FirstOrDefault(x => x.AttributeType.Name == "DisplayAttribute");

    if (displayAttribute != null)
    {
        displayName = displayAttribute.NamedArguments.FirstOrDefault().TypedValue.Value;
    }

    return displayName;
}
MarchalPT
quelle