a constructor as a delegate - is it possible in C#?

匿名 (未验证) 提交于 2019-12-03 02:31:01

问题:

I have a class like below:

class Foo {   public Foo(int x) { ... } } 

and I need to pass to a certain method a delegate like this:

delegate Foo FooGenerator(int x); 

Is it possible to pass the constructor directly as a FooGenerator value, without having to type:

delegate(int x) { return new Foo(x); } 

?

EDIT: For my personal use, the question refers to .NET 2.0, but hints/responses for 3.0+ are welcome as well.

回答1:

Nope, the CLR does not allow binding delegates to ConstructorInfo.

You can however just create your own:

static T Make(Action init) where T : new() {   var t = new T();   init(t);   return t; } 

Usage

var t = Make( x => { x.Bar = "bar"; x.Baz = 1; }); 


回答2:

I'm assuming you would normally do something like this as part of a factory implementation, where the actual types aren't known at compile-time...

First, note that an easier approach may be a post-create init step, then you can use generics:

static T Create({args}) where T : class, ISomeInitInterface, new() {     T t = new T();     t.Init(args);     return t; } 

You can then use MakeGenericMethod and/or CreateDelegate.


Otherwise; you can do this with on the fly with Expression (3.5) or DynamicMethod (2.0).

The Expression approach is easier to code:

    var param = Expression.Parameter(typeof(int), "val");     var ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });     var lambda = Expression.Lambda>(         Expression.New(ctor, param), param);     var func = lambda.Compile();     Foo foo = func(123);     string s = foo.ToString(); // proof 

or (using 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 func = (Converter)         dm.CreateDelegate(typeof(Converter));             Foo foo = func(123);     string s = foo.ToString(); // proof 


回答3:

I think as concise as you're going to get (without moving to a factory pattern) would be something with anonymous methods, like this:

delegate Foo FooGenerator(int x);  ...      void DoStuff() {     YourDelegateConsumer(x => new Foo(x)); } 

This isn't doing strictly what you asked for (since you're passing a delegate to an anonymous method that returns a new instance, rather than a direct delegate to the constructor), but I don't think what you're asking for is strictly possible.

This is, of course, assuming you're using 3.5+



回答4:

It sounds like you probably want to be using the class factory pattern.

Factory Method Pattern



回答5:

Unfortunately not, constructors are not quite the same things as methods and as such you cannot create a delegate that points to them. This is an interesting idea though, perhaps with more information we could devise some sort of workaround that would be syntactically similar.



回答6:

Marc Gravell's answer inspired me to the following very simple solution:

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); } 

Almost the same thing if your constructor has params (in this example: 1 param of type int):

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 }); } 


回答7:

My guess is that it isn't possible since you would pass a method of an object that has not been created yet.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!