Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create delegate from constructor

Using reflection, I'm trying to create a delegate from a parameterless constructor like this:

Delegate del = GetMethodInfo( () => System.Activator.CreateInstance( type ) ).CreateDelegate( delType );

static MethodInfo GetMethodInfo( Expression<Func<object>> func )
{
    return ((MethodCallExpression)func.Body).Method;
}

But I get this exception: "Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type." What will work?

Note that CreateDelegate was moved, for this profile at least, since the previous version of .NET. Now it's on MethodInfo.

like image 315
HappyNomad Avatar asked May 15 '12 03:05

HappyNomad


People also ask

Can we create delegate to constructor in C#?

As phoog points out a constructor doesn't "return" a value; plus you get information about it with ConstructorInfo and not MethodInfo ; which means you can't create a delegate around it directly. You have to create code that invokes the constructor and returns the value. For example: var ctor = type.

How do you create a delegate?

A delegate can be declared using the delegate keyword followed by a function signature, as shown below. The following declares a delegate named MyDelegate . public delegate void MyDelegate(string msg); Above, we have declared a delegate MyDelegate with a void return type and a string parameter.

What is the correct way to define a delegate?

A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.


3 Answers

As phoog points out a constructor doesn't "return" a value; plus you get information about it with ConstructorInfo and not MethodInfo; which means you can't create a delegate around it directly. You have to create code that invokes the constructor and returns the value. For example:

var ctor = type.GetConstructor(Type.EmptyTypes);
if (ctor == null) throw new MissingMethodException("There is no constructor without defined parameters for this object");
DynamicMethod dynamic = new DynamicMethod(string.Empty,
            type,
            Type.EmptyTypes,
            type);
ILGenerator il = dynamic.GetILGenerator();

il.DeclareLocal(type);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);

var func = (Func<object>)dynamic.CreateDelegate(typeof(Func<object>));

Of course, if you don't know the type at compile time then you can only deal with Object...

like image 68
Peter Ritchie Avatar answered Oct 17 '22 05:10

Peter Ritchie


Try it:

Dictionary<Type, Delegate> cache = new Dictionary<Type, Delegate>();
public T Create<T>()
{
    if (!cache.TryGetValue(typeof(T), out var d))
        d = cache[typeof(T)]
            = Expression.Lambda<Func<T>>(
                Expression.New(typeof(T)),
                Array.Empty<ParameterExpression>())
            .Compile();
    return ((Func<T>)d)();
}

Reflection is very slow! Speed tests are here (in Russian): https://ru.stackoverflow.com/a/860921/218063

like image 43
Андрей NOP Avatar answered Oct 17 '22 05:10

Андрей NOP


It would not be very useful to have a delegate that points to a constructor, since constructors do not have a return value. The delegate would construct an object but give you no way of retaining a reference to it.

You can of course create delegates that return the newly-constructed object:

Func<object> theDelegate = () => new object();

You could also create a delegate from the Invoke() method of the constructor's ConstructorInfo

For other types of objects:

Func<string> theDelegate = () => new string('w', 3);
Func<SomeClassInMyProject> theDelegate = () => new SomeClassInMyProject();

The last line assumes there's an accessible parameterless constructor.

Update with CreateDelegate()

T CallConstructor<T>() where T : new() { return new T(); }
Delegate MakeTheDelegate(Type t)
{
    MethodInfo generic = //use your favorite technique to get the MethodInfo for the CallConstructor method
    MethodInfo constructed = generic.MakeGenericMethod(t);
    Type delType = typeof(Func<>).MakeGenericType(t);
    return constructed.CreateDelegate(delType);
}
like image 3
phoog Avatar answered Oct 17 '22 03:10

phoog