.NET の属性とは何ですか?それらは何に役立ちますか?独自の属性を作成するにはどうすればよいですか?
11 に答える
メタデータ。オブジェクト/メソッド/プロパティに関するデータ。
たとえば、DisplayOrder という属性を宣言すると、UI にプロパティを表示する順序を簡単に制御できます。次に、それをクラスに追加して、属性を抽出し、UI 要素を適切に並べ替える GUI コンポーネントを作成します。
public class DisplayWrapper
{
private UnderlyingClass underlyingObject;
public DisplayWrapper(UnderlyingClass u)
{
underlyingObject = u;
}
[DisplayOrder(1)]
public int SomeInt
{
get
{
return underlyingObject .SomeInt;
}
}
[DisplayOrder(2)]
public DateTime SomeDate
{
get
{
return underlyingObject .SomeDate;
}
}
}
これにより、カスタム GUI コンポーネントを操作するときに、SomeDate の前に SomeInt が常に表示されるようになります。
ただし、直接コーディング環境以外で最も一般的に使用されていることがわかります。たとえば、Windows デザイナはそれらを広範囲に使用するため、カスタムメイドのオブジェクトを処理する方法を知っています。BrowsableAttribute を次のように使用します。
[Browsable(false)]
public SomeCustomType DontShowThisInTheDesigner
{
get{/*do something*/}
}
たとえば、設計時に [プロパティ] ウィンドウの使用可能なプロパティにこれをリストしないように設計者に指示します。
また、コード生成、プリコンパイル操作 (Post-Sharp など)、または Reflection.Emit などのランタイム操作にも使用できます。たとえば、プロファイリング用のコードを少し書いて、コードが行うすべての呼び出しを透過的にラップし、時間を計ることができます。特定のメソッドに配置する属性を介して、タイミングを「オプトアウト」できます。
public void SomeProfilingMethod(MethodInfo targetMethod, object target, params object[] args)
{
bool time = true;
foreach (Attribute a in target.GetCustomAttributes())
{
if (a.GetType() is NoTimingAttribute)
{
time = false;
break;
}
}
if (time)
{
StopWatch stopWatch = new StopWatch();
stopWatch.Start();
targetMethod.Invoke(target, args);
stopWatch.Stop();
HandleTimingOutput(targetMethod, stopWatch.Duration);
}
else
{
targetMethod.Invoke(target, args);
}
}
それらを宣言するのは簡単です。Attribute から継承するクラスを作成するだけです。
public class DisplayOrderAttribute : Attribute
{
private int order;
public DisplayOrderAttribute(int order)
{
this.order = order;
}
public int Order
{
get { return order; }
}
}
また、属性を使用する場合、接尾辞「attribute」を省略できることを覚えておいてください。コンパイラがそれを追加します。
注:属性はそれ自体では何もしません - それらを使用する他のコードが必要です。コードが作成されている場合もありますが、自分で作成する必要がある場合もあります。たとえば、C# コンパイラはいくつかのフレームワークを考慮し、特定のフレームワーク フレームワークはいくつかを使用します (たとえば、NUnit はクラスで [TestFixture] を検索し、アセンブリをロードするときにテスト メソッドで [Test] を検索します)。
そのため、独自のカスタム属性を作成するときは、コードの動作にまったく影響を与えないことに注意してください。(リフレクションを介して) 属性をチェックし、それらに基づいて動作する他の部分を作成する必要があります。
多くの人が答えましたが、これまで誰もこれについて言及していません...
属性はリフレクションで頻繁に使用されます。反射はすでにかなり遅いです。
実行時のパフォーマンスを向上させるために、カスタム属性をクラスとしてマークすることは非常に価値があります。sealed
また、そのような属性を配置するのが適切な場所を検討し、属性(!)を属性として使用して、を介してこれを示すこともお勧めしますAttributeUsage
。利用可能な属性の使用法のリストはあなたを驚かせるかもしれません:
- 組み立て
- モジュール
- クラス
- 構造体
- 列挙型
- コンストラクタ
- 方法
- 財産
- 分野
- イベント
- インターフェース
- パラメータ
- 委任
- ReturnValue
- GenericParameter
- 全て
AttributeUsage属性がAttributeUsage属性の署名の一部であることもクールです。循環依存についてはおっ!
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
属性は、クラスをタグ付けするための一種のメタデータです。これは、たとえば WinForms でツールバーからコントロールを非表示にするためによく使用されますが、独自のアプリケーションに実装して、さまざまなクラスのインスタンスが特定の方法で動作できるようにすることもできます。
属性を作成することから始めます。
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
public class SortOrderAttribute : Attribute
{
public int SortOrder { get; set; }
public SortOrderAttribute(int sortOrder)
{
this.SortOrder = sortOrder;
}
}
すべての属性クラスが有効であるためには、サフィックス "Attribute" が必要です。
これが完了したら、属性を使用するクラスを作成します。
[SortOrder(23)]
public class MyClass
{
public MyClass()
{
}
}
次のようにして、特定のクラスを確認できますSortOrderAttribute
(クラスがある場合)。
public class MyInvestigatorClass
{
public void InvestigateTheAttribute()
{
// Get the type object for the class that is using
// the attribute.
Type type = typeof(MyClass);
// Get all custom attributes for the type.
object[] attributes = type.GetCustomAttributes(
typeof(SortOrderAttribute), true);
// Now let's make sure that we got at least one attribute.
if (attributes != null && attributes.Length > 0)
{
// Get the first attribute in the list of custom attributes
// that is of the type "SortOrderAttribute". This should only
// be one since we said "AllowMultiple=false".
SortOrderAttribute attribute =
attributes[0] as SortOrderAttribute;
// Now we can get the sort order for the class "MyClass".
int sortOrder = attribute.SortOrder;
}
}
}
これについてもっと知りたい場合は、かなり良い説明があるMSDNをいつでもチェックできます。
これがお役に立てば幸いです。
私が現在取り組んでいるプロジェクトには、さまざまなフレーバーの UI オブジェクトのセットと、これらのオブジェクトを組み立ててメイン アプリケーションで使用するページを作成するエディターがあり、DevStudio のフォーム デザイナーに少し似ています。これらのオブジェクトは独自のアセンブリに存在し、各オブジェクトはから派生したクラスUserControl
であり、カスタム属性を持っています。この属性は次のように定義されます。
[AttributeUsage (AttributeTargets::Class)]
public ref class ControlDescriptionAttribute : Attribute
{
public:
ControlDescriptionAttribute (String ^name, String ^description) :
_name (name),
_description (description)
{
}
property String ^Name
{
String ^get () { return _name; }
}
property String ^Description
{
String ^get () { return _description; }
}
private:
String
^ _name,
^ _description;
};
そして、私はそれを次のようなクラスに適用します:
[ControlDescription ("Pie Chart", "Displays a pie chart")]
public ref class PieControl sealed : UserControl
{
// stuff
};
これは、以前のポスターが言ったことです。
属性を使用するために、エディタにはGeneric::List <Type>
コントロール タイプを含む があります。ユーザーがページにドラッグ アンド ドロップして、コントロールのインスタンスを作成できるリスト ボックスがあります。リスト ボックスに入力するにControlDescriptionAttribute
は、コントロールの を取得し、リストにエントリを入力します。
// done for each control type
array <Object ^>
// get all the custom attributes
^attributes = controltype->GetCustomAttributes (true);
Type
// this is the one we're interested in
^attributetype = ECMMainPageDisplay::ControlDescriptionAttribute::typeid;
// iterate over the custom attributes
for each (Object ^attribute in attributes)
{
if (attributetype->IsInstanceOfType (attribute))
{
ECMMainPageDisplay::ControlDescriptionAttribute
^description = safe_cast <ECMMainPageDisplay::ControlDescriptionAttribute ^> (attribute);
// get the name and description and create an entry in the list
ListViewItem
^item = gcnew ListViewItem (description->Name);
item->Tag = controltype->Name;
item->SubItems->Add (description->Description);
mcontrols->Items->Add (item);
break;
}
}
注: 上記は C++/CLI ですが、C# に変換するのは難しくありません (ええ、C++/CLI は忌まわしいものですが、それは私が使用しなければならないものです :-( )
ほとんどのものに属性を付けることができ、事前定義された属性の全範囲があります。上記のエディターは、プロパティとその編集方法を説明するプロパティのカスタム属性も探します。
全体のアイデアを理解すると、それらなしでどうやって生きてきたのか不思議に思うでしょう.
属性は、コード内のオブジェクトに適用できるいくつかの機能を含むクラスです。これを作成するには、System.Attribute から継承するクラスを作成します。
それらが何に適しているかというと…それらにはほとんど無限の用途があります.
属性は、クラス、メソッド、またはアセンブリに適用されるメタデータのようなものです。
それらは、さまざまなことに適しています (デバッガーの視覚化、古いものとしてマークする、シリアル化可能としてマークする、リストは無限にあります)。
独自のカスタムを作成するのは簡単です。ここから始める:
http://msdn.microsoft.com/en-us/library/sw480ze8(VS.71).aspx
前述のように、属性は比較的簡単に作成できます。作業の他の部分は、それを使用するコードを作成することです。ほとんどの場合、実行時にリフレクションを使用して、属性またはそのプロパティの存在に基づいて動作を変更します。コンパイルされたコードの属性を調べて、何らかの静的分析を行うシナリオもあります。たとえば、パラメーターが非 null としてマークされている場合、分析ツールはこれをヒントとして使用できます。
属性を使用し、それらを使用するための適切なシナリオを知ることは、作業の大部分です。
属性は、本質的に、型(クラス、メソッド、イベント、列挙型など)にアタッチしたいデータのビットです。
アイデアは、実行時に他のタイプ/フレームワーク/ツールが属性内の情報についてタイプを照会し、それに基づいて動作するということです。
したがって、たとえば、Visual Studio はサード パーティ コントロールの属性をクエリして、デザイン時にコントロールのどのプロパティを [プロパティ] ペインに表示する必要があるかを判断できます。
属性をアスペクト指向プログラミングで使用して、実行時にオブジェクトを装飾する属性に基づいてオブジェクトを挿入/操作し、オブジェクトのビジネス ロジックに影響を与えることなく、オブジェクトに検証、ログ記録などを追加することもできます。
属性の作成を開始するには、C# ソース ファイルを開き、attribute
[TAB] を入力して押します。新しい属性のテンプレートに展開されます。
サブクラスごとに同じコードを何度も記述することなく、サブクラスでタグ値を定義する簡単な方法としてカスタム属性を使用できます。独自のコードでカスタム属性を定義して使用する方法について、John Waters による簡潔な例を見つけました。
http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspxにチュートリアルがあります。
属性は、アスペクト指向プログラミングでも一般的に使用されます。この例については、PostSharpプロジェクトを確認してください。