3

拡張メソッドを使用して、クラスメンバー(フィールドのみ)のカスタム属性を確認したい。

public class DatabaseIdAttribute : Attribute
{
    public int ID { get; set; }

    public DatabaseIdAttribute(int id)
    {
        this.ID = id;
    }
}

public class MyClass 
{
    [DatabaseId(1)]
    double Height {get;set;}

    [DatabaseId(2)]
    double Width {get;set;}

    double Area { get { return this.Height * this.Width; }
}

マジックストリングを渡す代わりに、拡張メソッドでLINQ式を使用してクラスフィールドにアクセスしたいと思います。

var myClass = new MyClass();
var attribute = myClass.GetAttribute<DatabaseIdAttribute>(c => c.Height);

達成することは可能ですか?

[編集]

とりあえず、@leppieの助けを借りて次のことを達成しました

    public static MemberInfo GetMember<T, R>(this T instance, Expression<Func<T, R>> selector)
    {
        var member = selector.Body as MemberExpression;
        if (member != null)
        {
            return member.Member;
        }
        return null;
    }

    public static T GetAttribute<T>(this MemberInfo member) where T : Attribute
    {
        return member.GetCustomAttributes(false).OfType<T>().SingleOrDefault();
    }

これにより、次の方法で属性を取得できます

var c = new MyClass();
var attribute = c.GetMember(m => m.Height).GetAttribute<DatabaseIdAttribute>();

でも次のようにアクセスできるようにしたい

var c = new MyClass();
var attribute = c.GetAttribute<DatabaseIdAttribute>(m => m.Height);
4

2 に答える 2

8

もうすぐです!これは機能するはずです(テストされていません)。

public static class ObjectExtensions
{
    public static MemberInfo GetMember<T,R>(this T instance, 
         Expression<Func<T, R>> selector)
    {
        var member = selector.Body as MemberExpression;
        if (member != null)
        {
            return member.Member;
        }
        return null;
    }

    // unnecessary in .NET 4.5 and up, see note!
    public static T GetAttribute<T>(this MemberInfo meminfo) where T : Attribute
    {
       return meminfo.GetCustomAttributes(typeof(T)).FirstOrDefault() as T;
    }
}

使用法:

var attr = someobject.GetMember(x => x.Height).
              GetAttribute<DatabaseIdAttribute>();

注:.NET 4.5以降(.NET Coreを含む)では、BCLは上記で定義されたメソッドと同じように機能するGetCustomAttribute<T>(MemberInfo)拡張メソッドGetAttributeを提供し、可能な場合は代わりに使用する必要があります。

于 2013-03-25T07:12:47.697 に答える
1

追加のジェネリック型を指定してもかまわない場合は、次のように実行できます。

public static class ReflectionHelper
{
    public static TAttr GetAttribute<TClass, TProp, TAttr>(Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
    {
        var member = selector.Body as MemberExpression;
        return member.Member.GetCustomAttributes<TAttr>(false).First();
    }
}

次に、次のように使用できます。

var attribute = ReflectionHelper.GetAttribute<MyClass, double, DatabaseIdAttribute>(m => m.Height);

これは拡張メソッドではないことに注意してください(静的拡張を使用できないため)。したがって、クラスのインスタンスを作成する必要はありません。

もちろん、拡張メソッドのバージョンを使用することもできます。

public static TAttr GetAttribute<TClass, TProp, TAttr>(this TClass instance, Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
{
   var member = selector.Body as MemberExpression;
   return member.Member.GetCustomAttributes<TAttr>(false).First();
}

それはあなたがそれをそのように呼ぶことを可能にするでしょう:

var c = new MyClass();
var attribute = c.GetAttribute<MyClass, double, DatabaseIdAttribute>(m => m.Height);

しかし、どちらの方法も非常に冗長です。コンパイルですべてのジェネリック型を推測する場合は、属性のインスタンスを渡す必要があります。

public static class ReflectionHelper
{
    public static TAttr GetAttribute<TClass, TProp, TAttr>(TAttr attribute, Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
    {
        var member = selector.Body as MemberExpression;
        return member.Member.GetCustomAttributes<TAttr>(false).First();
    }
}

使用法:

var attribute = ReflectionHelper.GetAttribute(new DatabaseIdAttribute(), m => m.Height);
于 2014-06-11T07:47:41.297 に答える