I have a System.Reflection.MethodInfo and would like to have a method that creates a delegate(preferably a Func<...> or an Action<...>) that represents that method, given an instance to invoke it on.
So ideally I would like something like the following psuedo-code:
public TDelegate GetMethod<TDelegate>(MethodInfo methodToRepresent, object instanceToInvokeOn)
{
return (TDelegate)((parameters....) => methodToRepresent.Invoke(instanceToInvokeOn, all parameters in an object[]));
}
where TDelegate represents the signature of the represented method. If the signatures don't match, an exception should be thrown.
I realise I probably can't achieve this with a simple lambda expression, since its parametertypes must be known at compile-time. Perhaps I need to construct a delegate from scratch? Is it possible to create a delegate by specifying its body and parameters seperately?
Thank you
I don't really understand your question. But perhaps you want this:
public TDelegate GetMethod<TDelegate>(MethodInfo methodToRepresent, object instanceToInvokeOn)
where TDelegate:class
{
return (TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate), instanceToInvokeOn, methodToRepresent);
}
You can do this with the following method. Note that you can't really create a generic Action<...> using this method because, as you say, the types are not known at compile time. But this gets you pretty close.
public delegate void DynamicInvokeDelegate(params object[] args);
public static DynamicInvokeDelegate CreateDynamicInvokeDelegate(MethodInfo method, object instance) {
return args => method.Invoke(instance, args);
}
If you need the delegate to return a value:
public delegate object DynamicInvokeWithReturnDelegate(params object[] args);
public static DynamicInvokeWithReturnDelegate CreateDynamicInvokeWithReturnDelegate(MethodInfo method, object instance) {
return args => method.Invoke(instance, args);
}
EDIT:
It actually looks like you might be wanting this code:
public static T GetDelegate<T>(MethodInfo method, object instance)
where T : class
{
return (T)(object)Delegate.CreateDelegate(typeof(T), instance, method);
}
The (object) cast is required, since the compiler will not allow you to cast Delegate to any random type, and you cannot constrain T to be a delegate. Casting through object satisfies the compiler.
Related
I want to create dynamic assembly with generic class:
class TestClass<T> where T : new() {
public T TestMethod() {
return f();
}
private Func<T> f;
}
So, I created class, added generic argument, set constraints and created delegate like this:
var fieldType = typeof(Func<>).MakeGenericType(TArg);
// TArg = testClassBuilder.DefineGenericParameters("T")[0];
Then using IL generator I tried to emit calling Invoke method:
ilGenerator.Emit(OpCodes.Callvirt, fieldType.GetMethod("Invoke"));
But I get NotSupportedException on GetMethod("Invoke") call. So, how to call this delegate using Emit?
You cannot call GetMethod on typeof(Func<>).MakeGenericType(TArg), because in this instance, TArg is a GenericTypeParameterBuilder, and the Type object returned by MakeGenericType doesn't know how to get the relevant methods.
Instead use TypeBuilder.GetMethod like this:
ilGenerator.Emit(
OpCodes.Callvirt,
TypeBuilder.GetMethod(
typeof(Func<>).MakeGenericType(genParam),
typeof(Func<>).GetMethod("Invoke")
));
I need to be able to pass an arbitrary method to some function myFunction:
void myFunction(AnyFunc func) { ... }
It should be possible to execute it with other static, instance, public or private methods or even delegates:
myFunction(SomeClass.PublicStaticMethod);
myFunction(SomeObject.PrivateInstanceMethod);
myFunction(delegate(int x) { return 5*x; });
Passed method may have any number of parameters and any return type. It should also be possible to learn the actual number of parameters and their types in myFunction via reflection. What would be AnyFunc in the myFunction definition to accommodate such requirements? It is acceptible to have several overloaded versions of the myFunction.
The Delegate type is the supertype of all other delegate types:
void myFunction(Delegate func) { ... }
Then, func.Method will give you a MethodInfo object you can use to inspect the return type and parameter types.
When calling the function you will have to explicitly specify which type of delegate you want to create:
myFunction((Func<int, int>) delegate (int x) { return 5 * x; });
Some idea of what you're trying to accomplish at a higher level would be good, as this approach may not turn out to be ideal.
Have the method accept a Delegate, rather than a particular delegate:
void myFunction(Delegate func)
{
}
Lets say I have a function
public void func1<T>();
And another function:
public void func2(Type type);
Inside func2, I want to call func1 with type. how can I "Convert" the type so it can fit in?
edit:
I didn't thought it will matter, but func1 is not my function. it part of the framework:
context.CreateObjectSet<T>()
You cannot call the generic function explicitly because you do not know the type at compile time. You can use reflections to call func1 and specify your type as generic argument. However I would advise you to change the signature of the methods to avoid using reflections if possible.
Here is an example of how to do it with Reflections:
private static void Method1(Type type)
{
MethodInfo methodInfo = typeof(Program).GetMethod("Method2", BindingFlags.NonPublic | BindingFlags.Static);
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(type);
genericMethodInfo.Invoke(null, null);
}
private static void Method2<T>()
{
Console.WriteLine(typeof(T).FullName);
}
You would have to use reflection.
public void func2(Type type)
{
// call func1<T>()
var thisType = this.GetType();
var method = thisType.GetMethod("func1", new Type[0]).MakeGenericMethod(type);
method.Invoke(this, null);
}
Another option, of course: you can simply go the other direction and make the Type version the "real" one:
public T func1<T>()
{
func2(typeof(T));
}
public object func2(Type type)
{
Console.WriteLine(type.FullName);
}
This is similar to how the framework implements Enum.TryParse<TEnum> and Enum.TryParseEnum. The implementation of the generic TEnum variant simply passes it along (via typeof(TEnum)) to the non-generic (Type-based) method.
Edit: Changed the wrong term boxing to casting.
I have the following problem:
If I create a new Delegate of type Action or Func it will be casted to a type of Delegate.
var #delegate = Delegate.CreateDelegate(type, #object, methodInfo);
But I need for a generic class the right casted object.
Consider following example:
class Example<T> {
Type GenericType() {
return typeof(T);
}
}
static Example<T> Create<T>(T #delegate) {
return new Example<T>();
}
Example.Create(#delegate).GenericType();
This will return Delegate as type, since this was the type of the casted object (#delegate).
One solution could be to cast the delegate like so:
if(#delegate is Action)
Example.Create((Action)#delegate).GenericType();
But since Delegate.CreateDelegate could also create Action or Func delegates, it is impossible to check all variations.
I can't change the generic class, so i must cast the delegate.
I hope i was able to explain my problem. I am not a native English speaker...
Edit: The Problem is that typeof(T) not return the "real" type of the object. But i'm afraid there is no solution.
What's wrong with #delegate.GetType() to get the actual type of the delegate?
Also, a side note: you are misusing the term "boxing".
If you can use .net 4.0 then your above works if you cast to dynamic
Example.Create((dynamic)#delegate).GenericType();
If you cannot, then you just have to do a little reflection and abstraction.
abstract class Example{
abstract Type GenericType();
}
class Example<T>:Example {
override Type GenericType() {
return typeof(T);
}
}
static Example Create(Delegate #delegate) {
return (Example)Activator.CreateInstance(typeof(Example<>).MakeGenericType(new []{#delegate.GetType()}));
}
To answer my own question: It is not possible. :(
I feel like I'm so close to working this out and have read dozens of articles and existing questions.
I have a method like this:
public T DoStuff(object arg1, object arg2)
{
/* Do stuff and return a T */
}
And I need to be able to pass this method to another class for callback purposes.
However, when this other class calls back it will do so with a different expected return type that is only known at runtime.
E.g.:
public void SomeMethod(MethodInfo m, ref object caller)
{
MethodInfo callback = m.MakeGenericMethod(new Type[] { runtimeType });
callback.Invoke(caller, new [] { arg1val, arg2val });
}
/* DoStuff() will make a call to SomeMethod() passing
* itself (the method and the object) */
However, instead of this I would like to be able to
Pass only a single callback object (i.e. a delegate or Func<>) to SomeMethod.
Be able to modify this object appropriately for the generic call.
Have type-safe parameters for the call as I would with a delegate/Func<>.
I've found approaches that suit each of these individually but none that covers all of them.
Is it possible?
From the MakeGenericMethod usage, I assume that the method (in your example) is generic in T:
public T DoStuff<T>(object arg1, object arg2)
Given the amount of reflection you are doing, this simply isn't doing you any favors; for use from reflection you might as well use:
public object DoStuff(Type type, object arg1, object arg2)
And use (for example) Activator.CreateInstance(type) to create an instance. The above can now be used with a delegate; for example a Func<Type,object,object,object>.