簡體   English   中英

如何從C#中的對象實例獲取自定義屬性

[英]How to get a custom attribute from object instance in C#

假設我有一個名為Test的類,其一個名為Title的屬性帶有一個自定義屬性:

public class Test
{
    [DatabaseField("title")]
    public string Title { get; set; }
}

還有一個擴展方法稱為DbField。 我想知道是否甚至可以在c#中從對象實例獲取自定義屬性。

Test t = new Test();
string fieldName = t.Title.DbField();
//fieldName will equal "title", the same name passed into the attribute above

能做到嗎?

這是一種方法。 擴展方法可以工作,但並不是那么容易。 我創建一個表達式,然后檢索自定義屬性。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    public class DatabaseFieldAttribute : Attribute
    {
        public string Name { get; set; }

        public DatabaseFieldAttribute(string name)
        {
            this.Name = name;
        }
    }

    public static class MyClassExtensions
    {
        public static string DbField<T>(this T obj, Expression<Func<T, string>> value)
        {
            var memberExpression = value.Body as MemberExpression;
            var attr = memberExpression.Member.GetCustomAttributes(typeof(DatabaseFieldAttribute), true);
            return ((DatabaseFieldAttribute)attr[0]).Name;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var p = new Program();
            Console.WriteLine("DbField = '{0}'", p.DbField(v => v.Title));

        }
        [DatabaseField("title")]
        public string Title { get; set; }

    }
}
namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Test t = new Test();

            Console.WriteLine(t.FieldName("Title").FieldName<DatabaseFieldAttribute>());
            Console.WriteLine(t.FieldName("Title").FieldIsPrimaryKey<DatabaseFieldAttribute>());
        }


    }

    public class Test
    {
        [DatabaseField("titlezzz", true)]
        public string Title
        {
            get;
            set;
        }
    }


    public class BaseDatabaseFieldAttribute : Attribute
    {
        private readonly string _name;

        public string Name { get { return _name; } }

        public BaseDatabaseFieldAttribute(string name)
        {
            _name = name;
        }
    }
    public class DatabaseFieldAttribute : BaseDatabaseFieldAttribute
    {
        private readonly bool _isPrimaryKey;

        public bool IsPrimaryKey { get { return _isPrimaryKey; } }

        public DatabaseFieldAttribute(string name, bool isPrimaryKey): base(name)
        {
            _isPrimaryKey = isPrimaryKey;
        }
    }

    public static class Helper
    {

        public static PropertyInfo FieldName(this object obj, string propertyName)
        {
            return obj.GetType().GetProperty(propertyName);
        }

        public static string FieldName<T>(this PropertyInfo property) where T: BaseDatabaseFieldAttribute
        {
            object[] os = property.GetCustomAttributes(typeof(T), false);

            if (os != null && os.Length >= 1)
                return (os[0] as T).Name;
            else
                return "N/A";
        }

        public static bool? FieldIsPrimaryKey<T>(this PropertyInfo property) where T : DatabaseFieldAttribute
        {
            object[] os = property.GetCustomAttributes(typeof(T), false);

            if (os != null && os.Length >= 1)
                return (os[0] as T).IsPrimaryKey;
            else
                return null;
        }
    }


}

是的,但是最終這將是一種回旋的方式,因為您將通過在公開該屬性的實例上調用GetType來獲取Type實例,然后對其進行處理(通常不這樣做)。

在這種情況下,您的擴展方法將無法獲取屬性信息,因為您要傳遞給它的只是一個字符串。

最終,您需要從中獲取PropertyInfo東西。 其他答案都指向Type ,它們缺少的是,這不是在想要的PropertyInfo處獲取屬性信息的唯一方法。

您可以通過向Type實例傳遞一個大概帶有屬性名稱的字符串來實現,因此您可以在Type上調用GetProperty

自C#3.0起,執行此操作的另一種方法是擁有一個使用Expression<T> ,然后使用Expression的各個部分來獲取PropertyInfo 在這種情況下,您將使用Expression<Func<string>>TResult為string的內容。

一旦有了PropertyInfo ,就可以在其上調用GetCustomAttributes並查找您的屬性。

表達式方法的優點是Expression<T>源自LambdaExpression ,您可以對其調用Compile ,然后在需要時調用以獲得實際值。

正如已經指出的那樣,使用原始發布者描述的語法是不可能的,因為您無法在擴展方法內獲得對PropertyInfo的引用。 像這樣的事情呢:

// Extension method
public static string GetDbField(this object obj, string propertyName)
{
    PropertyInfo prop = obj.GetType().GetProperty(propertyName);
    object[] dbFieldAtts = prop.GetCustomAttributes(typeof(DatabaseFieldAttribute), true);

    if (dbFieldAtts != null && dbFieldAtts.Length > 0)
    {
        return ((DatabaseFieldAttribute)dbFieldAtts[0]).Name;
    }

    return "UNDEFINED";
}

然后,您可以簡單地獲取信息:

Test t = new Test();
string dbField = t.GetDbField("Title");

不,不可能。 這樣做的原因是,將值發送給獲取此信息的任何自定義擴展方法,而不是屬性本身。 一旦進入該擴展方法,就沒有可靠的方法可以追溯到屬性本身。

枚舉值可能是可能 ,但是就POCO的屬性而言,它是行不通的。

為了獲得屬性值,您需要屬性適用的類型。 您的擴展方法僅獲得一個字符串值(Title的值),因此您將無法獲取該字符串來自的實際實例,因此也無法獲得Title屬性所屬的原始類型。 這將使得無法從擴展方法中獲取屬性值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM