C# – 現在のアセンブリでインターフェイスを実装するすべての型を読み込みます

指定されたインターフェイスを実装する現在のアセンブリ内のすべての型を取得するには、次を使用します:

private IEnumerable<Type> GetAllTypesThatImplementInterface<T>()
{
	return System.Reflection.Assembly.GetExecutingAssembly()
		.GetTypes()
		.Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);
}
Code language: C# (cs)

これらのタイプのインスタンスを作成するには、それらをループして、次のように Activator.CreateInstance() を使用します。

foreach (var type in GetAllTypesThatImplementInterface<T>())
{
	var instance = (T)Activator.CreateInstance(type);

	//do something with instance
}
Code language: C# (cs)

例 – コマンド ルーティング テーブルの自動配線

コマンドルーティングテーブルを構築したいとしましょう。コマンドがあり、コマンド ハンドラーを自動的に接続したいと考えています。

これは、Web API の仕組みに似ています。コントローラーが処理するルートを指定します。リクエストが来ると、ウェブ フレームワークはそのルートを処理するコントローラーを自動的に呼び出します。

コマンド ハンドラ インターフェースを作成する

public interface ICommandHandler
{
	string HandlesCommand { get; }
	void Handle(string command, string data);
}
Code language: C# (cs)

コマンド ルーティング テーブルを作成する

これにより、ICommandHandler インターフェイスを実装するすべての型が読み込まれ、コマンド => コマンド ハンドラーのマップが作成されます。

public class CommandRoutingTableBuilder
{
	public Dictionary<string, ICommandHandler> GetCommandRoutingTable()
	{
		var commandRoutingTable = new Dictionary<string, ICommandHandler>();

		foreach (var type in GetAllTypesThatImplementInterface<ICommandHandler>())
		{
			var handler = (ICommandHandler)Activator.CreateInstance(type);

			commandRoutingTable.Add(handler.HandlesCommand, handler);
		}

		return commandRoutingTable;
	}
	private IEnumerable<Type> GetAllTypesThatImplementInterface<T>()
	{
		return System.Reflection.Assembly.GetExecutingAssembly()
			.GetTypes()
			.Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);
	}
}
Code language: C# (cs)

コマンドを実装する ハンドラー

この動作を示すために、単純なコマンド ハンドラーを作成します。コンソールにデータを 2 回書き込むことで、「繰り返し」コマンドを処理します。

public class RepeatDataCommandHandler : ICommandHandler
{
	public string HandlesCommand => "repeat";

	public void Handle(string command, string data)
	{
		Console.WriteLine($"I repeat: {data} {data}");
	}
}
Code language: C# (cs)

ルーティング テーブルを使用してコマンドを自動的に処理する例

static void Main(string[] args)
{
	var commandRoutingTable = new CommandRoutingTableBuilder().GetCommandRoutingTable();

	string command = "repeat";
	string data = "hello world";

	commandRoutingTable[command].Handle(command, data);
}
Code language: C# (cs)

RepeatDataCommandHandler は「repeat」コマンドにマップされるため、このコードは RepeatDataCommandHandler.Handle() を呼び出し、「I repeat:hello world hello world」をコンソールに出力します。