【发布时间】:2021-05-15 08:27:30
【问题描述】:
我有一个应用程序获取外部应用程序的 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 和我的methodName = Print,那么methodInfo 为空。
我的问题
- 关于
Delegate.CreateDelegate,我有什么不理解/遗漏的地方? - 我遗漏了哪些代码没有按预期工作?
- 是否有不同的方法来做同样的事情?
- 从创建委托开始,我想稍后在代码中调用它,但是直接在 methodinfo 上使用调用而不是创建委托然后调用它是否会受到惩罚?
- 如果省略
BindingFlags.Instance,为什么methodinfo 不给我我的公共非静态成员?
【问题讨论】:
-
如果你这样做
method.CreateDelegate(typeof(Func<string, string>), instance)会发生什么?您使用了错误的类型,例如Print需要使用Func<string, int, string> -
@Charlieface 感谢您的反馈。这部分
Func<string, int, string>帮助很大。我将给出一个更详细的答案来说明代码现在工作时的样子。我现在基本上有Delegate.CreateDelegate(Func<string, int, string>, instance, methodinfo)回答你问的问题,实例是一个对象,创建委托的第二个参数需要方法信息 -
您需要确定您期望的函数签名,即哪些参数和返回类型。您必须有一个具有相同签名的代表。
PrintStatic和PrintPrivate是相同的Func<string, string>但PrintVoid想要一个Action<string> -
@Charlieface 谢谢。你帮了大忙。即使真正的代码不关心空白,您的回答也非常有帮助。我将使用最终代码创建一个答案,并为将来可能需要它的任何人提供帮助。简而言之,我最终得到了这个
Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), instance, method); -
我要说的是,如果你不知道类型,那么委托就没有多大意义。
CreateDelegate的全部意义在于有一个静态类型的委托可以在没有反射的情况下使用,但是这样你也需要反射来调用委托。
标签: c# delegates invoke argumentexception methodinfo