Так что вам нужно вещь, которая может создавать экземпляры неизвестного типа, который реализует интерфейс. У вас есть в основном три варианта: фабричный объект, объект типа или делегат. Вот как данность:
public interface IInterface
{
void DoSomething();
}
public class Foo : IInterface
{
public void DoSomething() { /* whatever */ }
}
Использование Тип довольно некрасиво, но имеет смысл в некоторых сценариях:
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());
}
Преимущество здесь в том, что код короткий и простой, может работать с любой метод построения и (с закрытием) позволяет легко передавать дополнительные данные, необходимые для построения объектов.