2

我有一个方法和两个委托,如下所示。它以这种方式运行。但我想使用 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();
    }
}
4

2 回答 2

2

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

可以将方法的第一个参数直接绑定到委托中,但不需要附加参数。在您的情况下,实例this是第一个参数,您不能为i.

我想您的误解是具有默认值的参数如何工作。它们仍然是调用者需要填写的参数。只是 C# 编译器会为您执行此操作。

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

于 2012-10-19T12:23:35.900 回答
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);
于 2012-10-19T12:25:26.860 回答