プロパティに属性があるかどうかを確認する


158

属性付きのクラスのプロパティが与えられた場合-特定の属性が含まれているかどうかを判断する最も速い方法は何ですか?例えば:

    [IsNotNullable]
    [IsPK]
    [IsIdentity]
    [SequenceNameAttribute("Id")]
    public Int32 Id
    {
        get
        {
            return _Id;
        }
        set
        {
            _Id = value;
        }
    }

たとえば、「IsIdentity」属性があることを確認する最も速い方法は何ですか?

回答:


279

属性をすばやく取得する方法はありません。しかし、コードは次のようにする必要があります(Aaronaughtの功績):

var t = typeof(YourClass);
var pi = t.GetProperty("Id");
var hasIsIdentity = Attribute.IsDefined(pi, typeof(IsIdentity));

属性のプロパティを取得する必要がある場合

var t = typeof(YourClass);
var pi = t.GetProperty("Id");
var attr = (IsIdentity[])pi.GetCustomAttributes(typeof(IsIdentity), false);
if (attr.Length > 0) {
    // Use attr[0], you'll need foreach on attr if MultiUse is true
}

63
属性の存在を確認するだけで、情報を取得する必要がない場合、を使用Attribute.IsDefinedすると、1行のコードと醜い配列/キャストを削除できます。
Aaronaught、2010年

4
私がこれに遭遇したのは、いくつかの属性が属性名とは異なるタイプを持っていることです。たとえばSystem.ComponentModel.DataAnnotations.Schemaで「NotMappedは」として使用されている[NotMapped]クラスではなく、それはあなたが使用する必要が検出するAttribute.IsDefined(pi, typeof(NotMappedAttribute))
Qjimbo

2
一般的なオーバーロードを使用する方が簡単な場合がありますIsIdentity[] attr = pi.GetCustomAttributes<IsIdentity>(false);
。– Mojtaba

@Qjimbo(またはおそらく他の誰かが読んでいる)属性は通常、名前の「属性」の部分なしで使用されますが、使用することもできます。規約ではそれを除外することができるため、通常、実際のタイプの名前の最後には属性がありますが、使用されません。
ジム・ウォルフ

44

.NET 3.5を使用している場合は、式ツリーを試すことができます。反射より安全です:

class CustomAttribute : Attribute { }

class Program
{
    [Custom]
    public int Id { get; set; }

    static void Main()
    {
        Expression<Func<Program, int>> expression = p => p.Id;
        var memberExpression = (MemberExpression)expression.Body;
        bool hasCustomAttribute = memberExpression
            .Member
            .GetCustomAttributes(typeof(CustomAttribute), false).Length > 0;
    }
}

7
参考までに、あなたの回答について質問されました。stackoverflow.com/questions/4158996/…–
グレッグ、

12

共通(汎用)メソッドを使用して、特定のMemberInfoの属性を読み取ることができます

public static bool TryGetAttribute<T>(MemberInfo memberInfo, out T customAttribute) where T: Attribute {
                var attributes = memberInfo.GetCustomAttributes(typeof(T), false).FirstOrDefault();
                if (attributes == null) {
                    customAttribute = null;
                    return false;
                }
                customAttribute = (T)attributes;
                return true;
            }

7

@Hans Passantによる回答を更新または拡張するには、プロパティの取得を拡張メソッドに分離します。これには、GetProperty()メソッドで厄介な魔法の文字列を削除するという追加の利点があります。

public static class PropertyHelper<T>
{
    public static PropertyInfo GetProperty<TValue>(
        Expression<Func<T, TValue>> selector)
    {
        Expression body = selector;
        if (body is LambdaExpression)
        {
            body = ((LambdaExpression)body).Body;
        }
        switch (body.NodeType)
        {
            case ExpressionType.MemberAccess:
                return (PropertyInfo)((MemberExpression)body).Member;
            default:
                throw new InvalidOperationException();
        }
    }
}

テストは2行に削減されます

var property = PropertyHelper<MyClass>.GetProperty(x => x.MyProperty);
Attribute.IsDefined(property, typeof(MyPropertyAttribute));

7

(私のような)ポータブルクラスライブラリPCLでそれを実行しようとしている場合は、次のように実行できます。

public class Foo
{
   public string A {get;set;}

   [Special]
   public string B {get;set;}   
}

var type = typeof(Foo);

var specialProperties = type.GetRuntimeProperties()
     .Where(pi => pi.PropertyType == typeof (string) 
      && pi.GetCustomAttributes<Special>(true).Any());

その後、必要に応じて、この特別なプロパティを持つプロパティの数を確認できます。


7

これはnameof()、次のような新しいC#機能を使用して、タイプセーフな方法で式ツリーと拡張メソッドなしで実行できます。

Attribute.IsDefined(typeof(YourClass).GetProperty(nameof(YourClass.Id)), typeof(IsIdentity));

nameof()はC#6で導入されました


6

Attribute.IsDefinedメソッドを使用できます

https://msdn.microsoft.com/en-us/library/system.attribute.isdefined(v=vs.110).aspx

if(Attribute.IsDefined(YourProperty,typeof(YourAttribute)))
{
    //Conditional execution...
}

具体的に探しているプロパティを提供したり、次のようなリフレクションを使用してすべてのプロパティを反復処理したりできます。

PropertyInfo[] props = typeof(YourClass).GetProperties();

これはコンパイルされません。YourPropertyまたはYourAttributeの周りに[]を使用することはできません
ロールの

以前のすべての答えは、私が従ったクラス、プロパティ、および属性名に関する仮定を使用しています。
フランシスムジニャック2018

修正されたようです。
ロール

2

これはかなり古い質問ですが、私は

私のメソッドにはこのパラメーターがありますが、構築することができます:

Expression<Func<TModel, TValue>> expression

次に、メソッドでこれ:

System.Linq.Expressions.MemberExpression memberExpression 
       = expression.Body as System.Linq.Expressions.MemberExpression;
Boolean hasIdentityAttr = System.Attribute
       .IsDefined(memberExpression.Member, typeof(IsIdentity));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.