以下のようなクラスがあります:
class Foo
{
public Foo(int x) { ... }
}
そして、私はこのようなデリゲートを特定のメソッドに渡す必要があります:
delegate Foo FooGenerator(int x);
次のように入力せずに、コンストラクタをFooGenerator
値として直接渡すことは可能ですか?
delegate(int x) { return new Foo(x); }
?
編集:私の個人的な使用では、質問は.NET 2.0に言及していますが、3.0以降のヒント/応答も歓迎します。
いいえ、CLRではデリゲートをConstructorInfo
にバインドできません。
ただし、独自に作成することもできます。
static T Make<T>(Action<T> init) where T : new()
{
var t = new T();
init(t);
return t;
}
使用法
var t = Make<Foo>( x => { x.Bar = "bar"; x.Baz = 1; });
私は通常、ファクトリー実装の一部としてこのようなことを行うと想定していますが、実際の型はコンパイル時には不明です...
最初に、より簡単なアプローチは作成後の初期化ステップである場合があることに注意してください。次にジェネリックを使用できます。
static T Create<T>({args}) where T : class, ISomeInitInterface, new() {
T t = new T();
t.Init(args);
return t;
}
その後、MakeGenericMethod
やCreateDelegate
を使用できます。
さもないと; Expression
(3.5)またはDynamicMethod
(2.0)を使用すると、オンザフライでこれを実行できます。
Expression
アプローチはコーディングが簡単です:
var param = Expression.Parameter(typeof(int), "val");
var ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
var lambda = Expression.Lambda<Func<int, Foo>>(
Expression.New(ctor, param), param);
var func = lambda.Compile();
Foo foo = func(123);
string s = foo.ToString(); // proof
または(DynamicMethod
を使用):
ConstructorInfo ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
DynamicMethod dm = new DynamicMethod("Create", typeof(Foo),
new Type[] { typeof(int) }, typeof(Foo), true);
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Ret);
Converter<int, Foo> func = (Converter<int, Foo>)
dm.CreateDelegate(typeof(Converter<int, Foo>));
Foo foo = func(123);
string s = foo.ToString(); // proof
(ファクトリーパターンに移動せずに)取得するのと同じくらい簡潔な方法は、次のような匿名メソッドを使用したものになると思います。
delegate Foo FooGenerator(int x);
...
void DoStuff()
{
YourDelegateConsumer(x => new Foo(x));
}
これはあなたが要求したことを厳密に行っていません(コンストラクタに直接デリゲートするのではなく、新しいインスタンスを返す匿名メソッドにデリゲートを渡しているため)が、私はあなたが求めていることを考えていません厳密に可能です。
もちろん、これは3.5以上を使用していることを前提としています
おそらくクラスファクトリパターンを使用したいようです。
残念ながら、コンストラクタはメソッドとまったく同じではないため、それらを指すデリゲートを作成することはできません。これは興味深いアイデアですが、おそらくより多くの情報があれば、構文的に類似した何らかの回避策を考案できます。
Marc Gravellの答えは、次の非常に簡単な解決策に私を鼓舞しました。
static void Main()
{
Pet a = _MakeObject(typeof(Dog));
Pet b = _MakeObject(typeof(Cat));
}
private static Pet _MakeObject(Type type)
{
ConstructorInfo info = type.GetConstructor(new Type[0]);
return (Pet)info?.Invoke(null);
}
コンストラクターにパラメーターがある場合もほぼ同じです(この例では、int型の1つのパラメーター)。
static void Main()
{
Pet a = _MakeObject(typeof(Dog), 5);
Pet b = _MakeObject(typeof(Cat), 7);
}
private static Pet _MakeObject(Type type, int age)
{
ConstructorInfo info = type.GetConstructor(new [] { typeof(int) });
return (Pet)info?.Invoke(new object[] { age });
}
まだ作成されていないオブジェクトのメソッドを渡すので、それは不可能だと思います。