So I'm trying to create an open delegate that doesn't know the type of its target in advance. I'm not sure if that explains it correctly, let me show you:
class X
{
public bool test() { return false; }
}
static void Main()
{
var x = new X();
var runtimeType = x.GetType();
var method = runtimeType.GetMethod("test");
var del = ... INSERT CODE
Console.WriteLine(del(x)); // should output False
}
While Delegate.CreateDelegate(typeof(Func<X, bool>), method);
works, but I don't know the type of X
at compile time. What I'd like to do, is use typeof(Func<object, bool>)
but that's not possible.
I searched and found this article.
I cleaned up some of the code - here's the related bit for me:
public static class MethodInfoExtensions
{
private static Func<TArg0, TReturn> F0<T, TArg0, TReturn>(MethodInfo method)
where T : TArg0
{
var d = (Func<T, TReturn>)Delegate.CreateDelegate(typeof(Func<T, TReturn>), method);
return delegate(TArg0 target) { return d((T)target); };
}
public static T DelegateForCallMethod<T>(this MethodInfo targetMethod)
{
//string creatorName = (targetMethod.ReturnType == typeof(void) ? "A" : "F") + targetMethod.GetParameters().Length.ToString();
// this will just do in my case
string creatorName = "F0";
var methodParams = targetMethod.GetParameters();
var typeGenArgs = typeof(T).GetGenericArguments();
var signature = new Type[1 + methodParams.Length + typeGenArgs.Length];
int idx = 0;
signature[idx++] = targetMethod.DeclaringType;
var mParams = targetMethod.GetParameters();
for (int i = 0; i < mParams.Length; i++)
signature[idx++] = mParams[i].ParameterType;
for (int i = 0; i < typeGenArgs.Length; i++)
signature[idx++] = typeGenArgs[i];
var mth = typeof(MethodInfoExtensions).GetMethod(creatorName, BindingFlags.NonPublic | BindingFlags.Static);
var gen = mth.MakeGenericMethod(signature);
var res = gen.Invoke(null, new object[] { targetMethod });
return (T)res;
}
}
Now I can write (in INSERT CODE area) method.DelegateForCallMethod<Func<object, bool>>();
and when I call del(x)
it would execute x.test()
and output False
correctly!
The problem is, changing X
to be a struct
(which is my actual use-case) breaks it! :(
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has
been thrown by the target of an invocation. ---> System.ArgumentException: Error
binding to target method. at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throw
OnBindFailure) at Vexe.Runtime.Extensions.VexeTypeExtensions.F0[T,TArg0,TReturn](MethodInfo method) in c:\Users\vexe\Desktop\MyExtensionsAndHelpers\Source\Runtime\RuntimeExtensions\TypeExtensions.cs:line 24
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] argum
ents, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle
typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisib
ilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at Vexe.Runtime.Extensions.VexeTypeExtensions.DelegateForCallMethod[T](Method
Info targetMethod) in c:\Users\vexe\Desktop\MyExtensionsAndHelpers\Source\Runtime\RuntimeExtensions\TypeExtensions.cs:line 50
at Program.Main(String[] args) in c:\Users\vexe\Desktop\MyExtensionsAndHelpers\Solution\Test\Program2.cs:line 225
Any idea why this happens? and how to fix it?
Thanks!
Aucun commentaire:
Enregistrer un commentaire