属性とリフレクション
CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 44/70。
属性は、クラス、メソッド、プロパティなどのコード要素に付加するメタデータタグです。属性はコードの実行方法を直接変更するものではありませんが、実行時に読み取れる情報を提供します。リフレクションは、このメタデータを読み取る仕組みです。
対象の要素の上に角括弧で囲んで記述することで、属性を適用します。
[Obsolete("Use NewMethod instead")]
public void OldMethod() { }
[Serializable]
public class Person
{
public string Name { get; set; }
}Attributeを継承することでカスタム属性を作成できます。
public class AuthorAttribute : Attribute
{
public string Name { get; }
public AuthorAttribute(string name) => Name = name;
}
[Author("John")]
public class Calculator { }リフレクションを使うと、System.Reflection名前空間を使用して、実行時に型を調べたり属性を読み取ったりできます。
Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name); // Johnメソッドやプロパティを見つけて、それらを動的に呼び出すこともできます。
MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
Console.WriteLine(method.Name);Attribute とリフレクションは多くのフレームワークを支えています。シリアライゼーションライブラリはこれらを使用して JSON の出力を制御し、テストフレームワークはこれらを使用してテスト methods を発見し、依存性注入コンテナーはこれらを使用してサービスを自動的に接続します。
チャレンジ
簡単custom attributes と reflection を使用して、plugin としてマークされたクラスを自動的に見つけて説明する plugin discovery system を構築しましょう。これは、実際の framework が runtime で component、test method、または API endpoint を発見する方法に似ています。
コードを 3 つのファイルに分けて整理します。
PluginAttribute.cs:PluginSystemnamespace に custom attribute calledPluginAttributeを作成します。attribute は次の条件を満たす必要があります。Attributeから Inherit する- 2 つの read-only property を Have する:
Name(string) とVersion(string) - constructor を通じて both の値を Accept する
Plugins.cs:PluginSystemnamespace に複数の plugin class を作成します。いくつかにはPluginAttributeを付け、1 つには付けないようにします。ImageProcessor-[Plugin("Image Processor", "1.0")]でマークDataExporter-[Plugin("Data Exporter", "2.5")]でマークHelperUtility- いずれの attribute でもマークしない(これは単なる通常の class です)
Program.cs: main file で reflection を使用し、PluginAttributeを Have するすべての class を発見します。発見した各 plugin の情報を表示します。次の処理が必要です。- current assembly からすべての type を取得する
- each type について
PluginAttributeを check する - attribute の
NameおよびVersionproperty を抽出して表示する
System.Reflection を使用して type を inspect し、custom attribute を取得します。GetCustomAttribute<T>() method は attribute が存在しない場合に null を返すため、これを使用して実際の plugin である class を filter できます。
発見した各 plugin を、1 行に 1 つ、次の format で表示します。
Plugin: {Name} (v{Version})plugin は次の順序で表示してください。最初に ImageProcessor、次に DataExporter です。HelperUtility class には attribute がないため、output に表示されないようにします。
Expected output:
Plugin: Image Processor (v1.0)
Plugin: Data Exporter (v2.5)この challenge では、framework が attribute を marker として使用し、reflection によってそれらを発見する方法を示します - dependency injection container、serialization library、testing framework を支えているのも同じ technique です。
REQUIRED OUTPUT FORMAT:自分で試してみよう
using System;
using System.Reflection;
using PluginSystem;
class Program
{
public static void Main(string[] args)
{
// TODO: 現在のアセンブリからすべての型を取得する
// Hint: Assembly.GetExecutingAssembly().GetTypes() を使用する
// TODO: 各型をループして PluginAttribute を持っているか確認する
// Hint: type.GetCustomAttribute<PluginAttribute>() を使用する
// TODO: 属性が存在する場合、次の形式でプラグイン情報を出力する:
// Plugin: {Name} (v{Version})
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
5ポリモーフィズムとインターフェース
コンパイル時 vs 実行時ポリモーフィズムインターフェース vs 抽象クラス複数のインターフェース明示的なインターフェースアップキャストとダウンキャストまとめ - 図形計算機8オブジェクト指向の高度な概念
継承よりコンポジションジェネリクス (クラスとメソッド)デリゲートとイベント属性とリフレクションIDisposable と using ステートメント依存性の注入 (DI) の基礎自分で練習してみよう: C#オンラインコンパイラ