gpt4 book ai didi

c# - 打开目标类型未知的实例委托(delegate)?

转载 作者:行者123 更新时间:2023-11-30 17:45:09 25 4
gpt4 key购买 nike

所以我正在尝试创建一个事先不知道其目标类型的开放委托(delegate)。我不确定这是否解释正确,让我向您展示:

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
}

同时 Delegate.CreateDelegate(typeof(Func<X, bool>), method);有效,但我不知道 X 的类型在编译时。我想做的是使用 typeof(Func<object, bool>)但这是不可能的。

我搜索并找到了this文章。

我清理了一些代码 - 这是我的相关部分:

public static class MethodInfoExtensions
{
public 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;

for (int i = 0; i < methodParams.Length; i++)
signature[idx++] = methodParams[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;
}
}

现在我可以写了(在插入代码区域)method.DelegateForCallMethod<Func<object, bool>>();当我调用 del(x)它会执行 x.test()并输出 False正确!

问题是,改变X成为struct (这是我的实际用例)打破了它! :(

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

(该行是res = ...)

知道为什么会这样吗?以及如何解决?

谢谢!

编辑:我不想使用 MethodInfo.Invoke。这里的重点是创建一个调用速度比常规反射快得多的委托(delegate)。

编辑: 追查问题,似乎F0如果 X 则无法创建委托(delegate)是 struct - 可调用MethodInfoExtensions.F0<X, object, bool>(method);核实- 如果 X是一个class那么没问题!

编辑: 进一步简化,似乎Delegate.CreateDelegate(typeof(Func<X, bool>), method)如果 X 则无法绑定(bind)是struct !

编辑找到this - 几乎相同的问题。但是解决方案意味着有一个自定义委托(delegate),其参数类型(在我的例子中是 X)在编译时已知:(

最佳答案

所以问题是Delegate.CreateDelegate(typeof(Func<X, bool>), method)如果 X 则失败是 struct - 根据 this我应该创建自己的委托(delegate)并通过 ref。我这样做了,它起作用了,但现在如果我改回 class 就不起作用了!它再次开始为 class 工作但不是 struct如果我删除 ref !

给定这个启动代码:

class X
{
public bool test() { return false; }
}

var x = new X();
var runtimeType = x.GetType();
var method = runtimeType.GetMethod("test");

案例 1(如果 X 是类则有效)

delegate TReturn MyDelegate1<TArg0, TReturn>(TArg0 obj);

var del = Delegate.CreateDelegate(typeof(MyDelegate1<X, bool>), method) as MyDelegate1<X, bool>;
Console.WriteLine(del(x));

Case2(如果 X 是结构体则有效)

delegate TReturn MyDelegate2<TArg0, TReturn>(ref TArg0 obj);

var del = Delegate.CreateDelegate(typeof(MyDelegate2<X, bool>), method) as MyDelegate2<X, bool>;
Console.WriteLine(del(ref x));

现在为了用这个来调整原始代码,我必须有两个版本的委托(delegate):一个有 ref,另一个没有。在 DelegateForCallMethod 里面功能,我看看是否 DeclaringType因为输入方法是一个结构或类,并相应地使用适当的委托(delegate)类型(我什至不确定它是否会起作用)

如果可行,可能会更新以添加代码。

如果有人能解释发生了什么,我们将不胜感激。

编辑:开始吧——(绝对不是最漂亮的——我觉得我在做一些多余的事情):

    public delegate TReturn MethodInvoker<TArg0, TReturn>(TArg0 target);
public delegate TReturn MethodInvokerRef<TArg0, TReturn>(ref TArg0 target);

public static MethodInvoker<TArg0, TReturn> F0Class<T, TArg0, TReturn>(MethodInfo method)
where T : TArg0
{
var d = Delegate.CreateDelegate(typeof(MethodInvoker<T, TReturn>), method) as MethodInvoker<T, TReturn>;
return delegate(TArg0 target)
{
return d((T)target);
};
}

public static MethodInvokerRef<TArg0, TReturn> F0Struct<T, TArg0, TReturn>(MethodInfo method)
where T : TArg0
{
var d = Delegate.CreateDelegate(typeof(MethodInvokerRef<T, TReturn>), method) as MethodInvokerRef<T, TReturn>;
return delegate(ref TArg0 target)
{
var typed = (T)target;
return d(ref typed);
};
}

public static Func<TArg0, TReturn> DelegateForCallMethod<TArg0, TReturn>(this MethodInfo targetMethod)
{
var declType = targetMethod.DeclaringType;

var signature = new Type[3]
{
declType,
typeof(TArg0),
typeof(TReturn)
};

bool isValueType = declType.IsValueType;

string delegateCreator;
if (isValueType)
delegateCreator = "F0Struct";
else
delegateCreator = "F0Class";


var mth = typeof(VexeTypeExtensions).GetMethod(delegateCreator, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
var gen = mth.MakeGenericMethod(signature);
var res = gen.Invoke(null, new object[] { targetMethod });

if (isValueType)
{
var mir = (MethodInvokerRef<TArg, TReturn>)res;
return x => mir(ref x);
}

var mi = (MethodInvoker<TArg, TReturn>)res;
return x => mi(x);
}

用法:

var x = // ... usual startup code
var del = method.DelegateForCallMethod<object, bool>();
Console.WriteLine(del(x));

关于c# - 打开目标类型未知的实例委托(delegate)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28268378/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com