代码之家  ›  专栏  ›  技术社区  ›  kabucey

如何从C中的对象实例获取自定义属性#

  •  21
  • kabucey  · 技术社区  · 15 年前

    假设我有一个名为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
    

    能做到吗?

    6 回复  |  直到 12 年前
        1
  •  27
  •   Nick Randell    15 年前

    这是一个方法。扩展方法是可行的,但并不那么容易。我创建一个表达式,然后检索自定义属性。

    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; }
    
        }
    }
    
        2
  •  6
  •   garik    15 年前
    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;
            }
        }
    
    
    }
    
        3
  •  2
  •   Ken Kin    12 年前

    是的,但最终它将是一个迂回的方式,因为你将得到 Type 来自调用的实例 GetType 在公开属性的实例上,然后处理该属性(通常比不公开)。

    在这种特定情况下,扩展方法将无法获取属性信息,因为您传递给它的只是一个字符串。

    最终,你需要的是 PropertyInfo 对于来自的财产。其他答案是指 类型 ,它们缺少的是,这不是在 属性信息 你想要哪一个。

    你可以通过 类型 具有字符串的实例,可能具有属性名,因此可以调用 GetProperty 类型 .

    自C 3.0以来,另一种方法是使用 Expression<T> 然后使用 Expression 到达 属性信息 .在这种情况下,您需要 Expression<Func<string>> 或者什么地方 TResult 是字符串。

    一旦你有了 属性信息 你可以打电话 GetCustomAttributes 在上面,并查找您的属性。

    表达式方法的优点是 表达式<t> 来源于 LambdaExpression ,你可以打电话给 Compile 打开,然后调用以获取实际值(如果需要)。

        4
  •  1
  •   WayneC    15 年前

    正如前面所指出的,使用原始海报描述的语法是不可能的,因为在扩展方法中无法获得对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");
    
        5
  •  0
  •   David Morton    15 年前

    不,不可能。原因是它是值,而不是属性本身,它将被发送到任何将获取此信息的自定义扩展方法中。一旦进入扩展方法,就没有可靠的方法可以追溯到属性本身。

    可能是有可能的 for enum values 但就Poco的财产而言,它不起作用。

        6
  •  0
  •   NerdFury    15 年前

    为了获取属性值,需要应用属性的类型。您的扩展方法只获取字符串值(标题的值),因此您将无法获取该字符串的实际实例,因此无法获取标题属性所属的原始类型。这将使您无法从扩展方法中获取属性值。