मैं रनटाइम पर एक वर्ग पर एक विशेषता कैसे पढ़ूं?


106

मैं एक सामान्य विधि बनाने की कोशिश कर रहा हूं जो एक वर्ग पर एक विशेषता पढ़ेगी और रनटाइम पर उस मान को लौटाएगी। मैं यह कैसे करूँगा?

नोट: DomainName विशेषता डोमेन DomainNameAttribute की है।

[DomainName("MyTable")]
Public class MyClass : DomainBase
{}

जो मैं उत्पन्न करने की कोशिश कर रहा हूं:

//This should return "MyTable"
String DomainNameValue = GetDomainName<MyClass>();

1
आधिकारिक Microsoft लिंक: msdn.microsoft.com/en-us/library/71s1zwct.aspx
Mahesh

2
महत्वपूर्ण परिणाम प्रश्न कस्टम विशेषता वाले विधानसभा में सभी प्रकार पाने के लिए stackoverflow.com/questions/2656189/...
क्रिस Marisic

जवाबों:


235
public string GetDomainName<T>()
{
    var dnAttribute = typeof(T).GetCustomAttributes(
        typeof(DomainNameAttribute), true
    ).FirstOrDefault() as DomainNameAttribute;
    if (dnAttribute != null)
    {
        return dnAttribute.Name;
    }
    return null;
}

अपडेट करें:

किसी भी विशेषता के साथ काम करने के लिए इस विधि को और अधिक सामान्यीकृत किया जा सकता है:

public static class AttributeExtensions
{
    public static TValue GetAttributeValue<TAttribute, TValue>(
        this Type type, 
        Func<TAttribute, TValue> valueSelector) 
        where TAttribute : Attribute
    {
        var att = type.GetCustomAttributes(
            typeof(TAttribute), true
        ).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return valueSelector(att);
        }
        return default(TValue);
    }
}

और इस तरह का उपयोग करें:

string name = typeof(MyClass)
    .GetAttributeValue((DomainNameAttribute dna) => dna.Name);

6
सवाल का जवाब देने में आपके परिश्रम के लिए धन्यवाद!
ज़ाफिरो

1
इस विस्तार विधि को आगे टाइप सदस्य के प्रकार और सभी - या कम से कम सबसे अधिक - सदस्यइनफो को विस्तारित करके सामान्यीकृत किया जा सकता है । ऐसा करने से यह गुण, फ़ील्ड्स और यहां तक ​​कि ईवेंट से पढ़ने की अनुमति देने के लिए खुल जाएगा।
M.Babcock

4
अति जटिल। विशेषता मान का चयन करने के लिए लैम्ब्डा का उपयोग करने की कोई आवश्यकता नहीं है। यदि आप लैम्बडा लिखने के लिए पर्याप्त हैं, तो आप केवल फ़ील्ड तक पहुँचने के लिए पर्याप्त जानते हैं।
डारेल ली

const Filedस्थैतिक कक्षा में प्राप्त करने के लिए मैं इसे कैसे बढ़ा सकता हूं ?
अमीर 18

51

ऐसा करने के लिए पहले से ही एक एक्सटेंशन है।

namespace System.Reflection
{
    // Summary:
    //     Contains static methods for retrieving custom attributes.
    public static class CustomAttributeExtensions
    {
        public static T GetCustomAttribute<T>(this MemberInfo element, bool inherit) where T : Attribute;
    }
}

इसलिए:

var attr = typeof(MyClass).GetCustomAttribute<DomainNameAttribute>(false);
return attr != null ? attr.DomainName : "";

1
सच। लेकिन केवल .NET 4.5 और नया। मैं अभी भी लाइब्रेरी कोड विकसित कर रहा हूं, जहां मैं इस पद्धति का उपयोग नहीं कर सकता :(
andreas

15
System.Reflection.MemberInfo info = typeof(MyClass);
object[] attributes = info.GetCustomAttributes(true);

for (int i = 0; i < attributes.Length; i++)
{
    if (attributes[i] is DomainNameAttribute)
    {
        System.Console.WriteLine(((DomainNameAttribute) attributes[i]).Name);
    }   
}

5
और "var" का उपयोग नहीं करने के लिए +1, इसलिए यह समझना आसान है कि यह कैसे काम करता है।
RenniePet

यह संकलन नहीं है। लेकिन "System.Reflection.MemberInfo जानकारी = typeof (MyClass) .GetTypeInfo ();" डो
मार्सेल जेम्स

4

मैंने एक वर्ग में किसी भी सदस्य के लिए सदस्य विशेषताएँ प्राप्त करने के लिए डारिन दिमित्रोव के जवाब का इस्तेमाल किया (एक वर्ग के लिए विशेषताओं के बजाय)। मैं इसे यहां पोस्ट कर रहा हूं क्योंकि अन्य इसे उपयोगी पा सकते हैं:

public static class AttributeExtensions
{
    /// <summary>
    /// Returns the value of a member attribute for any member in a class.
    ///     (a member is a Field, Property, Method, etc...)    
    /// <remarks>
    /// If there is more than one member of the same name in the class, it will return the first one (this applies to overloaded methods)
    /// </remarks>
    /// <example>
    /// Read System.ComponentModel Description Attribute from method 'MyMethodName' in class 'MyClass': 
    ///     var Attribute = typeof(MyClass).GetAttribute("MyMethodName", (DescriptionAttribute d) => d.Description);
    /// </example>
    /// <param name="type">The class that contains the member as a type</param>
    /// <param name="MemberName">Name of the member in the class</param>
    /// <param name="valueSelector">Attribute type and property to get (will return first instance if there are multiple attributes of the same type)</param>
    /// <param name="inherit">true to search this member's inheritance chain to find the attributes; otherwise, false. This parameter is ignored for properties and events</param>
    /// </summary>    
    public static TValue GetAttribute<TAttribute, TValue>(this Type type, string MemberName, Func<TAttribute, TValue> valueSelector, bool inherit = false) where TAttribute : Attribute
    {
        var att = type.GetMember(MemberName).FirstOrDefault().GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return valueSelector(att);
        }
        return default(TValue);
    }
}

उपयोग उदाहरण:

//Read System.ComponentModel Description Attribute from method 'MyMethodName' in class 'MyClass'
var Attribute = typeof(MyClass).GetAttribute("MyMethodName", (DescriptionAttribute d) => d.Description);

व्युत्पन्न व्युत्पन्न गुणों पर काम नहीं करता है - इसके लिए, आपको एक अलग स्थैतिक विधि (System.Attribute.GetCustomAttributes) stackoverflow.com/a/7175762/184910
murraybische

3

डारिन दिमित्रोव के पहले समाधान का एक सरलीकृत संस्करण:

public string GetDomainName<T>()
{
    var dnAttribute = typeof(T).GetCustomAttribute<DomainNameAttribute>(true);
    if (dnAttribute != null)
    {
        return dnAttribute.Name;
    }
    return null;
}

2

यदि आपने http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx से पहले इसे नहीं देखा है तो यहां एक अच्छा ट्यूटोरियल है

विशेष रूप से आपकी रुचि के लिए यहां अनुभाग है, जिसे एक्सेसिंग एट्रीब्यूट कहा जाता है http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx#vcwlattattestestitorysor3


0
' Simplified Generic version. 
Shared Function GetAttribute(Of TAttribute)(info As MemberInfo) As TAttribute
    Return info.GetCustomAttributes(GetType(TAttribute), _
                                    False).FirstOrDefault()
End Function

' Example usage over PropertyInfo
Dim fieldAttr = GetAttribute(Of DataObjectFieldAttribute)(pInfo)
If fieldAttr IsNot Nothing AndAlso fieldAttr.PrimaryKey Then
    keys.Add(pInfo.Name)
End If

शायद जेनेरिक फ़ंक्शन इनलाइन के शरीर का उपयोग करना उतना ही आसान है। यह मेरे लिए कोई मतलब नहीं है फ़ंक्शन को MyClass प्रकार पर सामान्य बनाने के लिए।

string DomainName = GetAttribute<DomainNameAttribute>(typeof(MyClass)).Name
// null reference exception if MyClass doesn't have the attribute.

0

मामले में किसी को भी अशक्त परिणाम की आवश्यकता है और इसके लिए एनम, प्रॉपर्टीइन्फो और कक्षाओं में काम करने के लिए, यहां बताया गया है कि मैंने इसे कैसे हल किया। यह डारिन दिमित्रोव के अद्यतन समाधान का एक संशोधन है।

public static object GetAttributeValue<TAttribute, TValue>(this object val, Func<TAttribute, TValue> valueSelector) where TAttribute : Attribute
{
    try
    {
        Type t = val.GetType();
        TAttribute attr;
        if (t.IsEnum && t.GetField(val.ToString()).GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() is TAttribute att)
        {
            // Applies to Enum values
            attr = att;
        }
        else if (val is PropertyInfo pi && pi.GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() is TAttribute piAtt)
        {
            // Applies to Properties in a Class
            attr = piAtt;
        }
        else
        {
            // Applies to classes
            attr = (TAttribute)t.GetCustomAttributes(typeof(TAttribute), false).FirstOrDefault();
        }
        return valueSelector(attr);
    }
    catch
    {
        return null;
    }
}

उपयोग के उदाहरण:

// Class
SettingsEnum.SettingGroup settingGroup = (SettingsEnum.SettingGroup)(this.GetAttributeValue((SettingGroupAttribute attr) => attr.Value) as SettingsEnum.SettingGroup?);

// Enum
DescriptionAttribute desc = settingGroup.GetAttributeValue((DescriptionAttribute attr) => attr) as DescriptionAttribute;

// PropertyInfo       
foreach (PropertyInfo pi in this.GetType().GetProperties())
{
    string setting = ((SettingsEnum.SettingName)(pi.GetAttributeValue((SettingNameAttribute attr) => attr.Value) as SettingsEnum.SettingName?)).ToString();
}

0

बल्कि फिर बहुत सारे कोड लिखें, बस यह करें:

{         
   dynamic tableNameAttribute = typeof(T).CustomAttributes.FirstOrDefault().ToString();
   dynamic tableName = tableNameAttribute.Substring(tableNameAttribute.LastIndexOf('.'), tableNameAttribute.LastIndexOf('\\'));    
}

0

जब आपने एक ही नाम के साथ ओवरराइड विधियाँ दी हैं तो नीचे दिए गए सहायक का उपयोग करें

public static TValue GetControllerMethodAttributeValue<T, TT, TAttribute, TValue>(this T type, Expression<Func<T, TT>> exp, Func<TAttribute, TValue> valueSelector) where TAttribute : Attribute
        {
            var memberExpression = exp?.Body as MethodCallExpression;

            if (memberExpression.Method.GetCustomAttributes(typeof(TAttribute), false).FirstOrDefault() is TAttribute attr && valueSelector != null)
            {
                return valueSelector(attr);
            }

            return default(TValue);
        }

उपयोग: var someController = new SomeController (कुछ params); var str = typeof (SomeController) .GetControllerMethodAttributeValue (x => someController.SomeMethod (It.IsAny) (), (RouteAttribute मार्गपरिचय) => pathAttribute.Template);

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.