24

カスタム属性を持つ Title という 1 つのプロパティを持つ Test というクラスがあるとします。

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

これはできますか?

4

6 に答える 6

30

ここにアプローチがあります。拡張メソッドは機能しますが、それほど簡単ではありません。式を作成し、カスタム属性を取得します。

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

    }
}
于 2010-02-24T22:38:59.213 に答える
6
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;
        }
    }


}
于 2010-02-24T21:48:48.373 に答える
2

Typeそれはそうですが、プロパティを公開するインスタンスを呼び出しGetTypeてインスタンスを取得し、それで作業するため(多くの場合)、最終的には回り道になります。

この特定のケースでは、拡張メソッドに渡すのはすべて文字列であるため、拡張メソッドは属性情報を取得できません。

最終的に必要なのはPropertyInfo、プロパティを取得するためのものです。他の回答は を参照していますがType、不足しているのは、必要な属性情報を取得する唯一の方法ではPropertyInfoありません。

Typeおそらくプロパティ名を含む文字列でインスタンスを渡すことでそれを行うことができるのでGetPropertyType.

C# 3.0 以降、これを行う別の方法は、 を受け取り、Expression<T>の一部を使用してExpressionを取得するメソッドを持つことでしたPropertyInfo。この場合、文字列Expression<Func<string>>であるまたは何かを取りTResultます。

を取得したらPropertyInfo、それを呼び出しGetCustomAttributesて属性を探すことができます。

式アプローチの利点は、必要に応じて実際の値を取得するために呼び出すことができるExpression<T>から派生することです。LambdaExpressionCompile

于 2010-02-24T21:38:43.503 に答える
1

指摘されているように、拡張メソッド内で 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");
于 2010-02-24T22:14:14.640 に答える
0

いいえ、できません。この理由は、この情報をフェッチするカスタム拡張メソッドに送信されるのはプロパティ自体ではなく、値であるためです。その拡張メソッドに入ると、プロパティ自体にさかのぼる信頼できる方法はありません。

列挙型の値については可能かもしれませんが、POCO のプロパティに関する限り、うまくいきません。

于 2010-02-24T21:40:42.630 に答える
0

属性値を取得するには、属性が適用されるタイプが必要です。拡張メソッドは文字列値 (Title の値) のみを取得しているため、文字列の元の実際のインスタンスを取得できず、Title プロパティが属する元の型を取得できません。これにより、拡張メソッドから属性値を取得できなくなります。

于 2010-02-24T21:41:32.233 に答える