c# - CreateDelegate 错误:System.ArgumentException 无法绑定到目标方法
问题描述
我有一个应用程序获取外部应用程序的 dll,查看它以查找指定的类和方法。然后它methodinfo
从这个外部方法中获取,然后尝试通过创建一个委托Delegate.CreateDelegate
我不断得到
System.ArgumentException: 'Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.'
我已经去提取了一些代码,以便更容易共享和调试,以及编写一个小的简单的外部应用程序来读取。请看下面的代码:
作为库的外部应用程序示例 (.Net Framework 4.8)
using System;
namespace MethodLib
{
public class PrintText
{
public string Print(string textToPrint, int number)
{
return $"{ PrintPrivate(textToPrint) }: {number}";
}
public static string PrintStatic(string textToPrint)
{
return textToPrint;
}
public void PrintVoid(string textToPrint)
{
Console.WriteLine(textToPrint);
}
private string PrintPrivate(string textToPrint)
{
return $"This is { textToPrint }";
}
}
}
应用到 CreateDelegate
MethodInfo 创建
using System;
using System.Reflection;
namespace DelegateApp
{
public class PluginSupport
{
public MethodInfo GetMethodInfo(string methodName, string externalLocation)
{
var instance = Activator.CreateInstance(Assembly.LoadFrom(externalLocation)
.GetType("MethodLib.PrintText"));
var methodInfo = instance.GetType()
.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
return methodInfo;
}
}
}
创建代表零件
namespace DelegateApp
{
public class MethodGenerator
{
private PluginSupport _pluginSupport;
public MethodGenerator()
{
_pluginSupport = new PluginSupport();
}
public MethodDetails Create(string methodName, string path)
{
var method = _pluginSupport.GetMethodInfo(methodName, path);
if (Equals(method, null))
{
throw new KeyNotFoundException($"Method '{ methodName }' doesn't exist in class");
}
return new MethodDetails
{
MethodName = method.Name,
ComponentName = method.DeclaringType.Name,
FriendlyName = method.DeclaringType.Name,
Parameters = method.GetParameters(),
LogicalPath = method.DeclaringType.Assembly.Location,
Method = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), method)
};
}
}
}
我试过什么
所以阅读了很多不同的帖子,我收集到我正在使用的电话
(Func<string>)Delegate.CreateDelegate(typeof(Func<string>), method)
实际上仅适用于静态方法,并且由于我对所有公共方法感兴趣,因此我缺少目标/实例。
因此,从其他示例中,您需要创建实例并将其也传递进去,所以我使用了var myInstance = Actovator.CreateInstance
,然后也传递了这个变量,最终得到以下结果
(Func<string>)Delegate.CreateDelegate(typeof(Func<string>), myInstance, method)
我也试过用这个
public static Delegate CreateDelegate(Type type, Type target, string method, bool ignoreCase);
这一切都在不断地抛出
System.ArgumentException: 'Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.'
我让它工作的唯一一次是当我执行以下操作时:
methodName = PrintStatic
从外部应用程序
var methodInfo = instance.GetType()
.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
var deleg = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>),null, method)
当然这不是我想要的,因为这只对我来说是静态的,我也想要非静态的。但即使这样,如果我添加BindingFlags.Instance
到混合中,静态也会引发相同的错误。
如果我也删除BindingFlags.Instance
和 my methodName = Print
,则 methodInfo 为空。
我的问题
- 我不理解/缺少
Delegate.CreateDelegate
什么? - 我错过了什么代码,这没有按我的预期工作?
- 有没有不同的方法来做同样的事情?
- 从创建委托开始,我想稍后在代码中调用它,但是直接在 methodinfo 上使用调用而不是创建委托然后调用它是否会受到惩罚?
BindingFlags.Instance
如果省略,为什么 methodinfo 不给我我的公共非静态成员?
解决方案
感谢@Charlieface,我意识到我的签名类型与我创建委托不对应。
所以我最终在这个示例代码中结束的是在MethodGenerator
课堂上执行以下操作
parameters
从方法信息中获取- 遍历参数并将它们添加到类型列表中并获取每个参数的类型
- 构建一个
func
我不知道它需要的类型数量的地方,并用我从方法信息 + 输出类型中获得的参数数量替换这个数字 - 检查 if 方法
isstatic
并基于此将其设置为
methHead = method.IsStatic
? Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), null, method)
: Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), instance, method);
我猜这是一些复杂的代码,但它可以工作,并且需要对其进行改进或将其放入我们想要使用它的实际代码库中。但正如@Charlieface提到的if you don't know the type, there isn't much point to the delegate.
最后一段代码
public MethodDetails Create(string methodName, string path)
{
var method = _pluginSupport.GetMethodInfo(methodName, path);
if (Equals(method, null))
{
throw new KeyNotFoundException($"Method '{ methodName }' doesn't exist in class");
}
var instance = Activator.CreateInstance(method.DeclaringType);
List<Type> types = new List<Type>();
var methodPrams = method.GetParameters();
foreach (var item in methodPrams)
{
types.Add(Type.GetType(item.ParameterType.UnderlyingSystemType.FullName));
}
var funcType = typeof(Func<>);
var delegateFunc = Type.GetType(funcType.FullName.Replace("1", (methodPrams.Length + 1).ToString()));
Delegate methHead;
types.Add(typeof(string));
methHead = method.IsStatic
? Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), null, method)
: Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), instance, method);
return new MethodDetails
{
MethodName = method.Name,
ComponentName = method.DeclaringType.Name,
FriendlyName = method.DeclaringType.Name,
Parameters = method.GetParameters(),
LogicalPath = method.DeclaringType.Assembly.Location,
Method = methHead
};
}
推荐阅读
- c# - lambda 事件处理程序会导致什么样的内存泄漏?
- xamarin - 如何在 xamarin 表单中维护错误登录
- jenkins - 在进入阶段之前设置变量的声明性管道脚本
- javascript - 当我应用它时,我的纹理接缝出现在我的 3D 模型中
- php - Debian 9 - 安装“xdebug master”而不是“Xdebug v2.7.0beta1”
- machine-learning - 在 KMeans 集群上训练神经网络模型
- python - 连接包含数字和 nan 的多列文本文件
- groovy - Katalon 添加授权标头失败
- bash - 给函数一个数组,感叹号?
- android - 如何通过启用活动A中的开关按钮来关闭活动B中的开关按钮?