【问题标题】:CreateDelegate Error: System.ArgumentException Cannot bind to the target methodCreateDelegate 错误:System.ArgumentException 无法绑定到目标方法
【发布时间】: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&lt;string&gt;)Delegate.CreateDelegate(typeof(Func&lt;string&gt;), method) 实际上仅适用于静态方法,由于我对所有公共方法感兴趣,因此我缺少目标/实例。

所以在其他示例中,您需要创建实例并将其传递,所以我使用了var myInstance = Actovator.CreateInstance,然后也传递了这个变量,最终得到以下结果

(Func&lt;string&gt;)Delegate.CreateDelegate(typeof(Func&lt;string&gt;), 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 为空。

我的问题

  1. 关于Delegate.CreateDelegate,我有什么不理解/遗漏的地方?
  2. 我遗漏了哪些代码没有按预期工作?
  3. 是否有不同的方法来做同样的事情?
  4. 从创建委托开始,我想稍后在代码中调用它,但是直接在 methodinfo 上使用调用而不是创建委托然后调用它是否会受到惩罚?
  5. 如果省略BindingFlags.Instance,为什么methodinfo 不给我我的公共非静态成员?

【问题讨论】:

  • 如果你这样做method.CreateDelegate(typeof(Func&lt;string, string&gt;), instance)会发生什么?您使用了错误的类型,例如Print需要使用Func&lt;string, int, string&gt;
  • @Charlieface 感谢您的反馈。这部分Func&lt;string, int, string&gt; 帮助很大。我将给出一个更详细的答案来说明代码现在工作时的样子。我现在基本上有Delegate.CreateDelegate(Func&lt;string, int, string&gt;, instance, methodinfo)回答你问的问题,实例是一个对象,创建委托的第二个参数需要方法信息
  • 您需要确定您期望的函数签名,即哪些参数和返回类型。您必须有一个具有相同签名的代表。 PrintStaticPrintPrivate 是相同的 Func&lt;string, string&gt;PrintVoid 想要一个 Action&lt;string&gt;
  • @Charlieface 谢谢。你帮了大忙。即使真正的代码不关心空白,您的回答也非常有帮助。我将使用最终代码创建一个答案,并为将来可能需要它的任何人提供帮助。简而言之,我最终得到了这个Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), instance, method);
  • 我要说的是,如果你不知道类型,那么委托就没有多大意义。 CreateDelegate 的全部意义在于有一个静态类型的委托可以在没有反射的情况下使用,但是这样你也需要反射来调用委托。

标签: c# delegates invoke argumentexception methodinfo


【解决方案1】:

感谢 @Charlieface,我意识到我的签名类型与我创建委托的方式不对应。

所以我最终在这个示例代码中完成的是在 MethodGenerator 类中执行以下操作

  1. 从methodinfo获取parameters
  2. 遍历参数并将它们添加到类型列表中并获取每个参数的类型
  3. 构建一个func,我不知道它需要多少类型,并用我从方法信息+输出类型中获得的参数数量替换这个数字
  4. 检查方法 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
            };
        }

【讨论】:

    猜你喜欢
    • 2021-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多