パラメータを使用して変数タイプをインスタンス化するエレガントな方法はありますか?
-
01-07-2019 - |
質問
これは合法ではありません:
public class MyBaseClass
{
public MyBaseClass() {}
public MyBaseClass(object arg) {}
}
public void ThisIsANoNo<T>() where T : MyBaseClass
{
T foo = new T("whoops!");
}
これを行うには、T の型オブジェクトで何らかのリフレクションを行うか、Activator.CreateInstance を使用する必要があります。どちらもかなり厄介です。もっと良い方法はありますか?
解決
空のコンストラクター以外の特定のコンストラクター シグネチャを持つように T を制約することはできませんが、必要なシグネチャを持つファクトリ メソッドを持つように T を制約することはできます。
public abstract class MyBaseClass
{
protected MyBaseClass() {}
protected abstract MyBaseClass CreateFromObject(object arg);
}
public void ThisWorksButIsntGreat<T>() where T : MyBaseClass, new()
{
T foo = new T().CreateFromObject("whoopee!") as T;
}
ただし、このシナリオでは、Abstract Factory などの別の作成パターンを使用することをお勧めします。
他のヒント
いいえ。パラメーターを渡さない場合は、パラメーターなしのコンストラクターを要求するように型 param を制約できます。ただし、引数を渡す必要がある場合は、運が悪いです。
where T : MyBaseClass, new()
パラメーターのないパブリック コンストラクターでのみ動作します。それを超えて、activator.CreateInstance に戻ります (これは実際にはそれほど悪いことではありません)。
機能していないことがわかります。
しかし、何があなたをこれを妨げているのでしょうか?
public void ThisIsANoNo<T>() where T : MyBaseClass
{
MyBaseClass foo = new MyBaseClass("whoops!");
}
すべてが MyBaseClass から継承されるので、それらはすべて MyBaseClass になりますよね?
試してみましたが、これは機能します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ThisIsANoNo<MyClass>();
ThisIsANoNo<MyBaseClass>();
}
public class MyBaseClass
{
public MyBaseClass() { }
public MyBaseClass(object arg) { }
}
public class MyClass :MyBaseClass
{
public MyClass() { }
public MyClass(object arg, Object arg2) { }
}
public static void ThisIsANoNo<T>() where T : MyBaseClass
{
MyBaseClass foo = new MyBaseClass("whoops!");
}
}
}
所属していません StackOverflow