public class Class1
{
[DisplayName("Something To Name")]
public virtual string Name { get; set; }
}
Wie erhalte ich den Wert des DisplayName-Attributs in C #?
public class Class1
{
[DisplayName("Something To Name")]
public virtual string Name { get; set; }
}
Wie erhalte ich den Wert des DisplayName-Attributs in C #?
Antworten:
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);
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
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)
Attribute.GetCustomAttribute(MemberInfo, Type) :) msdn.microsoft.com/en-us/library/ms130863
In einer Ansicht mit Class1 als stark typisiertem Ansichtsmodell:
ModelMetadata.FromLambdaExpression<Class1, string>(x => x.Name, ViewData).DisplayName;
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();
GetName()Methode nur den Schlüssel und nicht den in der Ressourcendatei angegebenen Wert zurück.
.GetName()anstelle des obigen Codes zu verwenden, siehe das Problem, das ich mit dem obigen Code hier hatte: stackoverflow.com/questions/43827360/…
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;
}
}
}
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.
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.
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.
Angenommen, propertyals PropertyInfoTyp können Sie dies in einer einzigen Zeile tun:
property.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().Single().DisplayName
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);
}
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:
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;
}}
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;
}