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

Accepted answer
Score: 60

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

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

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

You 3 can then use MakeGenericMethod and/or CreateDelegate.


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

The 1 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
Score: 37

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

You can however just create your own:

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

Usage

var t = Make<Foo>( x => { x.Bar = "bar"; x.Baz = 1; });
Score: 9

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

delegate Foo FooGenerator(int x);

...    

void DoStuff()
{
    YourDelegateConsumer(x => new Foo(x));
}

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

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

Score: 6

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

Factory Method Pattern

Score: 2

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

Score: 2

Marc Gravell's answer inspired me to the 3 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 2 same thing if your constructor has params 1 (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 });
}
Score: 1

Another option would be to use the Activator class, like 1 so:

Using Generic Types

public delegate Foo FooGeneratorDelegate<T>(int x);

public T FooGeneratorFunction<T>(int x)
{
    return (T)Activator.CreateInstance(typeof(T), x);
}

// implementation example
FooGeneratorDelegate<Foo> del = FooGeneratorFunction<Foo>;
Foo foo = del(someIntValue);

Passing Your Type Foo as a Parameter

public delegate object FooGeneratorDelegate(Type t, int x);

public object FooGeneratorFunction(Type t, int x)
{
    return Activator.CreateInstance(t, x);
}

// implementation example
FooGeneratorDelegate del = FooGeneratorFunction;
Foo foo = (Foo)del(typeof(Foo), someIntValue);

If the Type will Always be of Type Foo

public delegate Foo FooGeneratorDelegate(int x);

public Foo FooGeneratorFunction(int x)
{
    return (Foo)Activator.CreateInstance(typeof(Foo), x);
}

// implementation example
FooGeneratorDelegate del = FooGeneratorFunction;
Foo foo = del(someIntValue);
Score: 1

While other answers only support parameter-less 3 constructor. Here is the version support 2 parameters. Hope it can help someone who 1 want to turn with-parameters ConsturctorInfo to Delegate.

public Delegate CreateDelegate(ConstructorInfo constructorInfo)
{
    var ctorParameters = constructorInfo.GetParameters();
    var lambdaParameters =
        ctorParameters.Select(x => Expression.Parameter(x.ParameterType, x.Name)).ToArray();
    var argsExp =
        ctorParameters.Select((p, i) => Expression.Convert(lambdaParameters[i], p.ParameterType));
    var newExp = Expression.New(constructorInfo, argsExp);
    var lambda = Expression.Lambda(newExp, lambdaParameters);
    return lambda.Compile();
}

Usage:

CreateDelegate(/* ConstructorInfo */).DynamicInvoke(args);

More Related questions