views:

703

answers:

6

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.

+3  A: 

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.

Andrew Hare
Could you possibly elaborate on the statement that "constructors are not quite (...) as methods" in context of delegates? I'd love especially some references to MSDN/C# reference/other docs.
akavel
+3  A: 

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

Factory Method Pattern

Mongus Pong
That's actually what I had used as a workaround, but for writing the question I thought the 'delegate' construct to be easier to understand.
akavel
A: 

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

Serge - appTranslator
+3  A: 

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+

Adam Robinson
+1; I'm actually compiling for 2.0, and that's why I had to work with "delegate", but as the core question is about something else, the lambda construct should surely be remembered.
akavel
+5  A: 

Nope, the CLR does not allow binding delegates 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; });
leppie
Could you possibly add some references (MSDN link?) for your statement about binding to ConstructorInfo?
akavel
A constructor does not produce a new object. A Constructor works in conjunction with an allocation routine.
sixlettervariables
@sixlettervariables: +1 - that looks like a reasonable explanation. That said, I'd still love to see some MSDN/C#-specification/... references from someone.
akavel
@akavel: Do I need to? http://msdn.microsoft.com/en-us/library/system.delegate.createdelegate.aspx, dig deeper in Reflector to see that requires a RuntimeMethodHandle.
leppie
`ConstructorInfo` != `MethodInfo`, hence a delegate cannot be created from a `ConstructorInfo` (as it isn't a Method).
sixlettervariables
akavel
+2  A: 

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<T>({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 easiest (examples on the way...)

    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

and

    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
Marc Gravell
Uh oh; technically, using reflection 2) AFAIK, reflection is slower than language-supported constructs, as it stacks one more level of abstraction.
akavel
Once compiled to a delegate, a reflection based approach is no slower, and can (on occasion) be faster, than regular compiled code. Obviously you only compile it once and cache the delegate.
Marc Gravell