Итак, вам нужна вещь , которая может создавать экземпляры неизвестного типа, реализующие интерфейс. У вас есть три основных варианта: объект фабрики, объект типа или делегат. Вот данные:
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 - это просто вспомогательный класс для классов, которые do предоставляют конструктор по умолчанию. Это самое простое и часто лучшее решение.
Третье, в настоящее время необычное, но, скорее всего, более распространенное, решение - это использование делегата:
public IInterface CreateUsingDelegate(Func<IInterface> createCallback)
{
return createCallback();
}
public void Test()
{
IInterface thing = CreateUsingDelegate(() => new Foo());
}
Преимущество здесь в том, что код короткий и простой, может работать с любым методом построения и (с замыканиями) позволяет легко передавать дополнительные данные, необходимые для построения объектов.