런타임에 클래스의 속성을 어떻게 읽습니까?


106

클래스의 속성을 읽고 런타임에 해당 값을 반환하는 일반 메서드를 만들려고합니다. 어떻게해야합니까?

참고 : DomainName 속성은 DomainNameAttribute 클래스입니다.

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

내가 생성하려는 것 :

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

1
공식 마이크로 소프트 링크 : msdn.microsoft.com/en-us/library/71s1zwct.aspx
Mahesh

답변:


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
질문에 답 해주셔서 감사합니다!
Zaffiro 2010

1
이 확장 메서드는 Type의 기본 클래스 인 MemberInfo와 Type 멤버의 전부 또는 최소한 대부분 을 확장하여 더욱 일반화 할 수 있습니다 . 이렇게하면 속성, 필드 및 이벤트에서 속성을 읽을 수 있도록이 창이 열립니다.
M.Babcock 2014-08-12

4
지나치게 복잡합니다. 속성 값을 선택하기 위해 람다를 사용할 필요가 없습니다. 람다를 작성하기에 충분하다면 필드에 액세스 할 수있을만큼 충분히 알고 있습니다.
Darrel Lee

이 접근 방식을 어떻게 확장 const Filed하여 정적 클래스 에 들어갈 수 있습니까?
Amir

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 2014

컴파일되지 않습니다. 하지만 "System.Reflection.MemberInfo info = typeof (MyClass) .GetTypeInfo ();" do
Marcel James

4

Darin Dimitrov의 답변을 사용하여 클래스의 모든 멤버에 대한 멤버 속성을 가져 오는 일반 확장을 만들었습니다 (클래스의 속성 대신). 다른 사람들이 유용하다고 생각할 수 있기 때문에 여기에 게시하고 있습니다.

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
murraybiscuit

3

Darin Dimitrov의 첫 번째 솔루션의 단순화 된 버전 :

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


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

누군가 nullable 결과가 필요하고 이것이 Enums, PropertyInfo 및 클래스에서 작동하려면 여기에 해결 방법이 있습니다. 이것은 Darin Dimitrov의 업데이트 된 솔루션을 수정 한 것입니다.

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 (Some params); var str = typeof (SomeController) .GetControllerMethodAttributeValue (x => someController.SomeMethod (It.IsAny ()), (RouteAttribute routeAttribute) => routeAttribute.Template);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.