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

C# 如何从C中的对象实例中获取自定义属性#,c#,.net,reflection,custom-attributes,C#,.net,Reflection,Custom Attributes,假设我有一个名为Test的类,它有一个名为Title的属性和一个自定义属性: public class Test { [DatabaseField("title")] public string Title { get; set; } } 以及一个名为DbField的扩展方法。我想知道在c#中是否可以从对象实例获取自定义属性 这可以做到吗?是的,但最终这将是一种迂回的方式,因为在公开属性的实例上调用GetType将获得Type实例,然后处理它(通常情况下) 在这种特定情况下,扩

假设我有一个名为Test的类,它有一个名为Title的属性和一个自定义属性:

public class Test
{
    [DatabaseField("title")]
    public string Title { get; set; }
}
以及一个名为DbField的扩展方法。我想知道在c#中是否可以从对象实例获取自定义属性


这可以做到吗?

是的,但最终这将是一种迂回的方式,因为在公开属性的实例上调用
GetType
将获得
Type
实例,然后处理它(通常情况下)

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

最终,您需要的是从中获取属性的
PropertyInfo
。其他答案涉及
类型
,它们缺少的是,这不是在
属性信息中获取所需属性信息的唯一方法

您可以通过传递一个带有字符串的
Type
实例(可能是属性名)来实现这一点,这样您就可以调用
Type
上的
GetProperty

自C#3.0以来的另一种实现方法是采用一个
表达式
,然后使用
表达式的部分
获取
属性信息
。在本例中,您将使用
表达式
TResult
为字符串的内容

一旦您拥有
属性info
,您就可以在其上调用
GetCustomAttributes
,并查找您的属性

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; }

    }
}

表达式方法的优点是
expression
派生自
LambdaExpression
,您可以调用
Compile
on,然后调用以获取实际值(如果需要)

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


这也许是可能的,但就POCO的属性而言,这是行不通的

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

命名空间控制台应用程序2
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;
        }
    }


}
{ 班级计划 { 静态void Main(字符串[]参数) { 测试t=新测试(); Console.WriteLine(t.FieldName(“Title”).FieldName(); Console.WriteLine(t.FieldName(“Title”).FieldIsPrimaryKey()); } } 公开课考试 { [数据库字段(“titlezzz”,真)] 公共字符串标题 { 得到; 设置 } } 公共类BaseDatabaseFieldAttribute:属性 { 私有只读字符串\u名称; 公共字符串名称{get{return{U Name;}} 公共BaseDatabaseFieldAttribute(字符串名称) { _名称=名称; } } 公共类DatabaseFieldAttribute:BaseDatabaseFieldAttribute { 私有只读bool\u isPrimaryKey; 公共bool IsPrimaryKey{get{return\u IsPrimaryKey;}} 公共数据库字段属性(字符串名称,bool isPrimaryKey):基(名称) { _isPrimaryKey=isPrimaryKey; } } 公共静态类助手 { 公共静态属性信息字段名(此对象对象对象,字符串属性名称) { 返回obj.GetType().GetProperty(propertyName); } 公共静态字符串FieldName(此PropertyInfo属性),其中T:BaseDatabaseFieldAttribute { object[]os=property.GetCustomAttributes(typeof(T),false); 如果(os!=null&&os.Length>=1) 返回(os[0]作为T).Name; 其他的 返回“不适用”; } public static bool?FieldIsPrimaryKey(此PropertyInfo属性),其中T:DatabaseFieldAttribute { object[]os=property.GetCustomAttributes(typeof(T),false); 如果(os!=null&&os.Length>=1) 返回(os[0]作为T).IsPrimaryKey; 其他的 返回null; } } }
正如前面所指出的,使用原始海报所描述的语法是不可能的,因为您无法在扩展方法中获得对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");

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

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; }

    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Linq.Expressions;
命名空间控制台应用程序1
{
公共类DatabaseFieldAttribute:属性
{
公共字符串名称{get;set;}
公共数据库字段属性(字符串名称)
{
this.Name=Name;
}
}
公共静态类MyClassExtensions
{
公共静态字符串DbField(此T obj,表达式值)
{
var memberExpression=value.Body作为memberExpression;
var attr=memberExpression.Member.GetCustomAttributes(typeof(DatabaseFieldAttribute),true);
返回((DatabaseFieldAttribute)attr[0]).Name;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
var p=新程序();
WriteLine(“DbField='{0}',p.DbField(v=>v.Title));
}
[数据库字段(“标题”)]
公共字符串标题{get;set;}
}