したがって、インターフェースを実装する未知のタイプのインスタンスを作成できるものが必要です。基本的に、ファクトリオブジェクト、Typeオブジェクト、またはデリゲートの3つのオプションがあります。これが与えられたものです:
public interface IInterface
{
void DoSomething();
}
public class Foo : IInterface
{
public void DoSomething() { /* whatever */ }
}
Typeの使用はかなり醜いですが、いくつかのシナリオでは理にかなっています。
public IInterface CreateUsingType(Type thingThatCreates)
{
ConstructorInfo constructor = thingThatCreates.GetConstructor(Type.EmptyTypes);
return (IInterface)constructor.Invoke(new object[0]);
}
public void Test()
{
IInterface thing = CreateUsingType(typeof(Foo));
}
それに関する最大の問題は、コンパイル時に、Fooが実際にデフォルトのコンストラクターを持っているという保証がないことです。また、これがパフォーマンスが重要なコードである場合、リフレクションは少し遅くなります。
最も一般的な解決策は、ファクトリを使用することです。
public interface IFactory
{
IInterface Create();
}
public class Factory<T> where T : IInterface, new()
{
public IInterface Create() { return new T(); }
}
public IInterface CreateUsingFactory(IFactory factory)
{
return factory.Create();
}
public void Test()
{
IInterface thing = CreateUsingFactory(new Factory<Foo>());
}
上記では、IFactoryが本当に重要です。Factoryは、デフォルトのコンストラクターを提供するクラスの便利なクラスです。これは最も単純で、多くの場合最良のソリューションです。
現在は一般的ではないが、より一般的になる可能性が高い3番目のソリューションは、デリゲートを使用することです。
public IInterface CreateUsingDelegate(Func<IInterface> createCallback)
{
return createCallback();
}
public void Test()
{
IInterface thing = CreateUsingDelegate(() => new Foo());
}
ここでの利点は、コードが短くて単純であり、任意の構築方法で機能し、(クロージャーを使用して)オブジェクトの構築に必要な追加データを簡単に渡すことができることです。