Constructor as a delegate - is this possible in C #?

I have a class as shown below:

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

and I need to pass the delegate to the specific method as follows:

 delegate Foo FooGenerator(int x); 

Is it possible to pass the constructor directly as a FooGenerator value without typing:

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

?

EDIT: For my personal use, the question is for .NET 2.0, but greetings / answers for version 3.0+ are also welcome.

+56
constructor c # delegates
Oct 21 '09 at 13:04
source share
7 answers

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

However, you can simply create your own:

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

Using

 var t = Make<Foo>( x => { x.Bar = "bar"; x.Baz = 1; }); 
+28
Oct 21 '09 at 13:15
source share
— -

I assume that you usually do something like this as part of a factory implementation where the actual types are not known at compile time ...

First, note that a simpler approach may be a step after creation, then you can use generics:

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

Then you can use MakeGenericMethod and / or CreateDelegate .




Otherwise; You can do this on the fly using 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<Func<int, Foo>>( 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<int, Foo> func = (Converter<int, Foo>) dm.CreateDelegate(typeof(Converter<int, Foo>)); Foo foo = func(123); string s = foo.ToString(); // proof 
+54
Oct 21 '09 at 15:35
source share

I think that the compressed, as you are going to get (without going to the factory template), will be something like anonymous methods, for example:

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

This does not strictly what you requested (since you pass the delegate to the anonymous method, which returns a new instance, and not a direct delegate to the constructor), but I don't think the request is strictly possible.

It is of course assumed that you are using 3.5+

+7
Oct 21 '09 at 13:15
source share

It looks like you probably want to use a factory class template.

Factory Method Template

+5
Oct 21 '09 at 13:10
source share

Unfortunately, the constructors are not exactly the same as the methods, and therefore you cannot create a delegate that points to them. This is an interesting idea, although perhaps with additional information we could develop some workaround that would be syntactically similar.

+2
Oct 21 '09 at 13:07
source share

Mark 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 if your constructor has parameters (in this example: 1 parameter 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 }); } 
+2
Jan 11 '16 at 13:05
source share

I assume this is not possible since you will pass a method to an object that has not yet been created.

0
Oct 21 '09 at 13:12
source share



All Articles