サーチ…


カスタム属性の作成

//1) All attributes should be inherited from System.Attribute
//2) You can customize your attribute usage (e.g. place restrictions) by using System.AttributeUsage Attribute
//3) You can use this attribute only via reflection in the way it is supposed to be used
//4) MethodMetadataAttribute is just a name. You can use it without "Attribute" postfix - e.g. [MethodMetadata("This text could be retrieved via reflection")].
//5) You can overload an attribute constructors
[System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Class)]
public class MethodMetadataAttribute : System.Attribute
{
    //this is custom field given just for an example
    //you can create attribute without any fields
    //even an empty attribute can be used - as marker
    public string Text { get; set; }

    //this constructor could be used as [MethodMetadata]
    public MethodMetadataAttribute ()
    {
    }

    //This constructor could be used as [MethodMetadata("String")]
    public MethodMetadataAttribute (string text)
    {
        Text = text;
    }
}

属性を使用する

[StackDemo(Text = "Hello, World!")]
public class MyClass
{
    [StackDemo("Hello, World!")]
    static void MyMethod()
    {
    }
}

属性を読み込む

メソッドGetCustomAttributesは、メンバーに適用されるカスタム属性の配列を返します。この配列を取得した後、1つまたは複数の特定の属性を検索できます。

var attribute = typeof(MyClass).GetCustomAttributes().OfType<MyCustomAttribute>().Single();

またはそれらを繰り返す

foreach(var attribute in typeof(MyClass).GetCustomAttributes()) {
    Console.WriteLine(attribute.GetType());
}

System.Reflection.CustomAttributeExtensions GetCustomAttribute拡張メソッドは、指定された型のカスタム属性を取得し、任意のMemberInfo適用できます。

var attribute = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute));

GetCustomAttributeには、検索する属性の種類を指定するための汎用シグネチャもあります。

var attribute = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>();

ブール引数のinheritは、これらのメソッドの両方に渡すinheritができます。この値をtrue設定すると、要素の祖先も検査されます。

DebuggerDisplay属性

DebuggerDisplay属性を追加すると、 DebuggerDisplayが上に乗ったときにデバッガがそのクラスを表示する方法が変更されます。

{}囲まれた式は、デバッガによって評価されます。これは、次のサンプルやより複雑なロジックのような単純なプロパティにすることができます。

[DebuggerDisplay("{StringProperty} - {IntProperty}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }
}

デバッガの表示例

閉じ括弧の前,nq追加すると、文字列を出力するときに引用符が削除されます。

[DebuggerDisplay("{StringProperty,nq} - {IntProperty}")]

{}では一般的な表現が許可されていますが、推奨されません。 DebuggerDisplay属性は、アセンブリメタデータに文字列として書き込まれます。 {}内の式の妥当性はチェックされません。したがって、より複雑なロジックを含むDebuggerDisplay属性、つまりC#ではうまくいくかもしれませんが、VB.NETで評価された同じ式は構文上有効ではなく、デバッグ中にエラーが発生します。

DebuggerDisplayを言語に依存しないようにする方法は、メソッドやプロパティに式を記述して代わりに呼び出すことです。

[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }

   private string DebuggerDisplay()
    {
        return $"{StringProperty} - {IntProperty}"";
    }
}

DebuggerDisplayがプロパティの全部または一部を出力し、オブジェクトのタイプもデバッグして調べることができます。
以下の例は、 DebuggerDisplayがデバッグ環境で使用されるため、ヘルパーメソッドを#if DEBUG囲みます。

[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }

#if DEBUG
   private string DebuggerDisplay()
    {
        return
            $"ObjectId:{this.ObjectId}, StringProperty:{this.StringProperty}, Type:{this.GetType()}";
    }
    #endif
}

発信者情報属性

呼び出し元情報属性を使用して、呼び出し元に関する情報を呼び出されたメソッドに渡すことができます。宣言は次のようになります。

using System.Runtime.CompilerServices;

public void LogException(Exception ex,
                         [CallerMemberName]string callerMemberName = "",
                         [CallerLineNumber]int callerLineNumber = 0,
                         [CallerFilePath]string callerFilePath = "")
{
    //perform logging
}

呼び出しは次のようになります。

public void Save(DBContext context)
{
    try
    {
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        LogException(ex);
    }
}

最初のパラメータのみが明示的にLogExceptionメソッドに渡され、残りはコンパイル時に関連する値とともに提供されることに注意してください。

callerMemberNameパラメータは、呼び出し元のメソッドの名前である"Save"という値を受け取り"Save"

callerLineNumberパラメーターは、いずれの行の数受け取るLogExceptionメソッド呼び出しがで書き込まれます。

また、 'callerFilePath'パラメータはSaveメソッドが宣言されているファイルのフルパスを受け取りSave

インタフェースから属性を読み取る

クラスはインタフェースから属性を継承しないため、インタフェースから属性を取得する簡単な方法はありません。インターフェイスを実装したり、派生クラス内のメンバーをオーバーライドする場合は常に、属性を再宣言する必要があります。したがって、以下の例では、3つのケースすべてでTrueが出力されます。

using System;
using System.Linq;
using System.Reflection;

namespace InterfaceAttributesDemo {
    
    [AttributeUsage(AttributeTargets.Interface, Inherited = true)]
    class MyCustomAttribute : Attribute {
        public string Text { get; set; }
    }
    
    [MyCustomAttribute(Text = "Hello from interface attribute")]
    interface IMyClass {
        void MyMethod();
    }
    
    class MyClass : IMyClass {
        public void MyMethod() { }
    }
    
    public class Program {
        public static void Main(string[] args) {
            GetInterfaceAttributeDemo();
        }
        
        private static void GetInterfaceAttributeDemo() {
            var attribute1 = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute), true);
            Console.WriteLine(attribute1 == null); // True
            
            var attribute2 = typeof(MyClass).GetCustomAttributes(true).OfType<MyCustomAttribute>().SingleOrDefault();
            Console.WriteLine(attribute2 == null); // True
            
            var attribute3 = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>(true);
            Console.WriteLine(attribute3 == null); // True
        }
    }
}

インターフェイス属性を取得する1つの方法は、クラスによって実装されたすべてのインターフェイスを通じてインターフェイス属性を検索することです。

var attribute = typeof(MyClass).GetInterfaces().SelectMany(x => x.GetCustomAttributes().OfType<MyCustomAttribute>()).SingleOrDefault();
Console.WriteLine(attribute == null); // False
Console.WriteLine(attribute.Text); // Hello from interface attribute

廃止された属性

System.Obsoleteは、より良いバージョンを持つ型またはメンバーをマークするために使用される属性であるため、使用しないでください。

[Obsolete("This class is obsolete. Use SomeOtherClass instead.")]
class SomeClass
{
    //
}

上記のクラスが使用されている場合、コンパイラは "This class is obsolete。SomeOtherClassを代わりに使用する"という警告を表示します。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow