如何使用Delegate.CreateDelegate而不是Func<>?来定义委托

时间:2012-10-19 12:17:53

标签: c# delegates func

我有一个方法和两个委托,如下所示。它以这种方式运行。但我想使用Delegate.CreateInstance。 dx和dy的类型必须为Func<IEnumerable<Foo>>。就像下面的fx和fy。它们不能是Func<int, IEnumerable<Foo>>

public class Test {
    private IEnumerable<T> CreateItems<T>(int count) where T : class
    {
        for (int i = 0; i < count; i++)
        {
            yield return (T)Activator.CreateInstance(typeof(T), i.ToString());
        }
    }

    public List<T> TestMethod<T>(int i = 1) where T : class
    {
        return CreateItems<T>(i).ToList();
    }

    public void TestRun()
    {
        const int Count = 5;
        Func<IEnumerable<Foo>> fx = () => this.TestMethod<Foo>(Count);
        Func<IEnumerable<Foo>> fy = () => this.TestMethod<Foo>();
        var lfx = fx.Invoke();
        var lfy = fy.Invoke();
        var dx = Delegate.CreateDelegate( ?? );
        var dy = Delegate.CreateDelegate( ?? );
        var ldx = dx.DynamicInvoke();
        var ldy = dy.DynamicInvoke();
    }
}

2 个答案:

答案 0 :(得分:2)

那是不可能的。您无法直接将带有签名A F(X x)实例方法放入Func<A>

可以直接将方法的第一个参数绑定到委托中,但不能添加其他参数。在您的情况下,实例this是第一个参数,您无法绑定i的值。

我猜你的误解是默认值的参数是如何工作的。它们仍然是调用者需要填写的参数。这只是C#编译器为你做的。

你需要一个带有正确签名的包装器。这可以是lambda或其他一些辅助方法。在您的情况下,我会重载方法TestMethod而不是使用默认参数。

答案 1 :(得分:2)

如果您希望类型为Func<IEnumerable<Foo>>,则无法通过Delegate.CreateDelegate直接创建 ,因为它们需要两个参数:实例(又名this ),和整数i。即使fx 中显示的表单还有i - 它恰好由编译器提供。如果TestMethod没有参数,可以通过以下方式完成:

var dy = (Func<IEnumerable<Foo>>) Delegate.CreateDelegate(
    typeof(Func<IEnumerable<Foo>>),
    this,
    GetType().GetMethod("TestMethod").MakeGenericMethod(typeof(Foo))
);

要动态执行此操作(部分应用程序),您需要创建一个具有实例(this)的类型,要注入的值(i)以及使用这些值调用 TestMethod<Foo>。这是完全编译器为您做的事情:

Func<IEnumerable<Foo>> fx = () => this.TestMethod<Foo>(Count);

这基本上创造了:

internal class <>_squiggle {
    public Test @this;
    public IEnumerable<Foo> Method() {
        return @this.TestMethod<Foo>(5);
    }
}

var capture = new <>_squiggle { @this = this };
var fx = new Func<IEnumerable<Foo>>(capture.Method);