内部コンストラクターを使用して一般的なクラスを作成します
-
01-10-2019 - |
質問
一般的な方法内で内部コンストラクターを含むオブジェクトを構築することは可能ですか?
public abstract class FooBase { }
public class Foo : FooBase {
internal Foo() { }
}
public static class FooFactory {
public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase, new() {
return new TFooResult();
}
}
FooFactory
と同じアセンブリに存在します Foo
. 。クラスは次のような工場の方法を呼び出します:
var foo = FooFactory.CreateFoo<Foo>();
コンパイル時間エラーを取得します:
'foo'は、一般的なタイプまたはメソッドfoofactory.createfoo() 'foofactory.createfoo()でパラメーター「tfootype」として使用するために、public parameterlessコンストラクターを備えた非アブストラクトタイプでなければなりません。
これを回避する方法はありますか?
私も試しました:
Activator.CreateInstance<TFooResult>();
これにより、実行時に同じエラーが発生します。
解決
削除できます new()
制約と返品:
//uses overload with non-public set to true
(TFooResult) Activator.CreateInstance(typeof(TFooResult), true);
クライアントもそれを行うことができますが。ただし、これはランタイムエラーが発生しやすいです。
この言語は抽象的なコンストラクターSuclaratonを許可しないため、これは安全な方法で解決するのが難しい問題です。
他のヒント
タイプの引数にはaが必要です 公衆 パラメーターレスコンストラクター。他の制約と一緒に使用する場合、新しい()制約を最後に指定する必要があります。
http://msdn.microsoft.com/en-us/library/d5x73970.aspx
編集:いいえ、New()Constraintを使用する場合、そのクラスを渡すことはできません。新しい()制約を使用しないと、リフレクションを使用して新しいインスタンスを作成することができます
public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase//, new()
{
return (TFooResult)typeof(TFooResult).GetConstructor(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] {}, null).Invoke(new object[]{});
//return new TFooResult();
}
以下のように作業アラウンドはほとんどありませんが、私はあなたがそのように行きたくないと思います!
タイプパラメーターのタイプに基づいてインスタンスを作成するスイッチステートメントを工場内に入れます。
FooBaseの各コンクリート実装は、工場の方法を通過するFoofactoryに登録して、自己を作成します。したがって、Foofactoryは内部辞書を使用します
タイプパラメーターとコンクリートの実装間のマッピングを除いて、同様の行で拡張することは、外部コード(XMLファイル、構成など)です。 IOC/DIコンテナもここで役立ちます。
public class GenericFactory
{
public static T Create<T>(object[] args)
{
var types = new Type[args.Length];
for (var i = 0; i < args.Length; i++)
types[i] = args[i].GetType();
return (T)typeof(T).GetConstructor(types).Invoke(args);
}
}