如何使C#Create.Delegate支持继承?

如何使C#Create.Delegate支持继承?,c#,.net,reflection,delegates,C#,.net,Reflection,Delegates,我有以下类型层次结构: public abstract class Parent { } public class Child : Parent { public Task SayAsync(string arg) { Console.WriteLine(arg); return Task.CompletedTask; } } 我需要做到以下几点: 在运行时创建Parent的任何实例(这已经通过调用Func解决了,我在代码的其他

我有以下类型层次结构:

public abstract class Parent { }
public class Child : Parent
{
    public Task SayAsync(string arg)
    {
        Console.WriteLine(arg);
        return Task.CompletedTask;
    }    
}
我需要做到以下几点:

  • 在运行时创建
    Parent
    的任何实例(这已经通过调用
    Func
    解决了,我在代码的其他地方获得了该实例)
  • 然后(在该实例上)调用所有
    public
    方法(它们总是返回
    任务
    并接受
    字符串
    作为参数),并传入非常量的
    arg
上述内容存在于热路径中,因此,为了提高性能,我将求助于
缓存的委托
,因此在启动时,我将创建委托,然后在需要时缓存并使用这些委托

下面是我为
Child
所做的一个显式示例,该示例很有效,但我无法弄清楚如何使委托接受
父级
(因为我在编译时不知道类型)

//如果我将Child更改为Parent,我会得到“无法绑定到目标方法,因为其签名或安全透明性与委托类型的签名或安全透明性不兼容”
私有委托任务调用程序(子实例,字符串arg);
void Main()
{
var instance=new Child();//这将通过调用Func获得
var methodWithArg=instance.GetType().GetMethod(“SaySync”);
var func=GetDelegateWithArg(methodWithArg);
func(例如“Foo”);
}
私有静态调用程序GetDelegateWithArg(MethodInfo方法)
{
对象指针=null;
return(Invoker)Delegate.CreateDelegate(typeof(Invoker)、指针、方法);
}

非常感谢任何有助于我实现目标的想法或备选方案。

您可以尝试使用表达式树生成代理:

public abstract class Parent { }

public class Child : Parent
{
    public Task SayAsync(string arg)
    {
        Console.WriteLine(arg);
        return Task.CompletedTask;
    }
}

public delegate Task Invoker(Parent instance, string arg);

class Program
{
    static void Main(string[] args)
    {
        Parent instance = new Child(); // This will be obtained by calling a Func<Parent>
        var methodWithArg = instance.GetType().GetMethod("SayAsync");

        var func = GetDelegateWithArg(methodWithArg);

        func(instance, "Foo");
    }

    private static Invoker GetDelegateWithArg(MethodInfo method)
    {
        var instanceParameter = Expression.Parameter(typeof(Parent));
        var argParameter = Expression.Parameter(typeof(string));
        var body = Expression.Call(
            Expression.Convert(instanceParameter, method.DeclaringType),
            method,
            argParameter);
        var lambda = Expression.Lambda<Invoker>(body, instanceParameter, argParameter);
        return lambda.Compile();
    }
}
公共抽象类父{}
公共类子级:父级
{
公共任务sayanc(字符串arg)
{
控制台写入线(arg);
返回Task.CompletedTask;
}
}
公共委托任务调用程序(父实例,字符串arg);
班级计划
{
静态void Main(字符串[]参数)
{
父实例=新的子实例();//这将通过调用Func获得
var methodWithArg=instance.GetType().GetMethod(“SaySync”);
var func=GetDelegateWithArg(methodWithArg);
func(例如“Foo”);
}
私有静态调用程序GetDelegateWithArg(MethodInfo方法)
{
var instanceParameter=Expression.Parameter(typeof(Parent));
var argParameter=Expression.Parameter(typeof(string));
var body=Expression.Call(
表达式.Convert(instanceParameter,方法.DeclaringType),
方法,,
参数);
var lambda=表达式.lambda(主体、instanceParameter、argParameter);
返回lambda.Compile();
}
}

生成的委托仍然非常快,尽管可能比Delegate.CreateDelegate()方法创建的委托慢一点。

可能尝试将目标实例传递给GetDelegateWithArg方法,并更改调用程序的签名以仅接收参数。大概是这样的:

private delegate Task Invoker(string arg);

private static Invoker GetDelegateWithArg(MethodInfo method, object target)
{            
    return (Invoker)Delegate.CreateDelegate(typeof(Invoker), target, method);
}
在建议的更改之后,您可以通过一个参数将实例传递给委托创建者和incoke func:

func("Foo");

这是一个有趣的答案,但有一个问题是,我需要在给定实例上执行每个调用,在您的解决方案中,我必须在每次创建一个实例时创建
委托。否?是的,您必须为每个实例创建委托。通过提供实例,您将确保该方法将在实例级别上创建,然后在给定实例上执行。您可以查看。感谢您的澄清,由于为每个实例创建委托的性能限制,我将无法使用此方法。但不管怎样,投票率还是上升了@到目前为止,帕维尔的答案正是我想要的。这太棒了!事实上,我通过将程序集标记为
[assembly:SecurityTransparent]
来补偿额外的开销,现在它比
委托更快
func("Foo");