3 に答える
このメカニズムで解決している問題について説明してください。それにアプローチするためのより明確な方法がある可能性が最も高いです。
編集
そして、はい、コードはにおいがします。単一の型に制約し、実行時例外を生成することを除いて、どの型に対しても空きを残しました。その場合、なぜタイプパラメータがあるのですか?
編集:この回答は、編集で質問が完全に切り替わる前に提供されたものであることに注意してください。そのため、最初に述べたように、質問にのみ存在していたものを指します。すべての「ダングリングポインタ」についてご容赦ください。:-)
短い答え:
あなたが投稿したコードでは、にキャストする代わりの方法は見当たりません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>
誤解しないでください。複数のオブジェクトタイプをサポートするファクトリメソッドが役立つ場合があることを認識しています。しかし、あなたの場合、それは価値があるよりも多くの問題を引き起こすようです。
PS:いくつかのIoCコンテナの1つの側面が面白いと思うかもしれません。これらは通常、構成する必要があります。これには、抽象インターフェースの具象型(つまり、実装クラス)を登録するプロセスが含まれます。たとえば(ここではAutofacを使用):
var builder = new ContainerBuilder();
builder.RegisterType<StringFoo>().As<IFoo<string>>();
その後、抽象型のオブジェクトインスタンスをリクエストできます。
using (var container = builder.Build())
{
var stringFoo = container.Resolve<IFoo<string>>();
...
}
このResolve
方法は興味深い部分です。抽象型を指定すると、登録された型を使用して、型の具体的なオブジェクトが返されますStringFoo
。それがあなたにとってやり過ぎのように聞こえないなら、それを調べてください!:-)
あなたはこのようなことを試すことができます...
public static class FooFactory
{
private static readonly Dictionary<Type, Type> FooTypesLookup;
static FooFactory()
{
FooTypesLookup = (from type in typeof(FooFactory).Assembly.GetExportedTypes()
let fooInterface =
type.GetInterfaces().FirstOrDefault(
x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IFoo<>))
where fooInterface != null
let firstTypeArgument = fooInterface.GetGenericArguments().First()
select new { Type = type, TypeArgument = firstTypeArgument })
.ToDictionary(x => x.TypeArgument, x => x.Type);
}
public static IFoo<T> CreateFoo<T>()
{
var genericArgumentType = typeof(T);
Type closedFooType;
return FooTypesLookup.TryGetValue(genericArgumentType, out closedFooType)
? (IFoo<T>) Activator.CreateInstance(closedFooType)
: null;
}
}
さらに良いことに、お気に入りのIoCコンテナー(Windsor、構造マップなど)を導入し、そこにIFooを実装するすべてのタイプを登録し、必要に応じてActivator.CreateInstance呼び出しの代わりにそれらを解決します。