Редактировать: Обратите внимание, что этот ответ был дан до того, как вопрос был полностью изменен при редактировании. Из-за этого он теперь относится к вещам, которые присутствовали только в вопросе, как было заявлено изначально. Прошу прощения за все "висячие указатели". : -)
Краткий ответ:
С кодом, который вы опубликовали, я не вижу альтернативы приведению к IFoo<T>
. Если вы этого не сделаете, компилятор выдаст предупреждение (по крайней мере, на моей машине).
Более подробный ответ:
Ваш код действительно должен быть таким? Точнее, нужен ли вам данный актерский состав?
Полагаю, вы собираетесь вызывать свой фабричный метод более или менее так:
var stringFoo = FooFactory.CreateFoo<string>();
Вы должны предоставить параметр шаблона (string
в этом случае) явно, потому что он не может быть получен из какого-либо аргумента метода (в этом случае, потому что на самом деле их вообще нет). Очевидно, что фабричный метод вернет IFoo<string>
.
Теперь, поскольку вы должны явно указать тип во время выполнения, вы можете написать:
var stringFoo = StringFoo.Create();
и поэтому внутри StringFoo
есть фабричный метод, который безоговорочно делает очевидным:
public class StringFoo : IFoo<string>
{
...
public static StringFoo Create() // or alternatively, return an IFoo<string>
{
return new StringFoo();
}
}
Применение этого шаблона также к другим IFoo<T>
реализациям сэкономит вам цепочку if
или switch
внутри FooFactory.CreateFoo<T>
, упростит ваш код и избавит от необходимости выполнять приведение (которое вы обеспокоены).
Не поймите меня неправильно, я знаю, что фабричные методы, поддерживающие более одного типа объекта , в некоторых случаях полезны; но, похоже, в вашем случае это вызывает больше проблем, чем стоит.
P.S.: Вам может быть интересен один аспект некоторых контейнеров IoC. Они обычно должны быть настроены, и это включает процесс, в котором вы регистрируете конкретные типы (то есть классы реализации) для абстрактных интерфейсов; например (здесь используется Autofac ):
var builder = new ContainerBuilder();
builder.RegisterType<StringFoo>().As<IFoo<string>>();
Затем вы можете запросить экземпляр объекта абстрактного типа:
using (var container = builder.Build())
{
var stringFoo = container.Resolve<IFoo<string>>();
...
}
Метод Resolve
является интересной частью. Вы предоставляете ему абстрактный тип, и, используя зарегистрированные типы, он возвращает конкретный объект типа StringFoo
. Посмотрите на это, если это не звучит как излишнее для вас! : -)