返回自己的C#委托

时间:2013-11-30 12:14:28

标签: c# lambda delegates

基本上我想要一个可以返回的委托。我有一个非常简单的减少我理论上想要的东西:

int i =0;
var x = () => 
{
    if (i > 10)
        return null;

    ++i;
    Debug.Log("keep going");
    return x;
};

var y = x;

while ((y = y()) != null) ;

预期的输出当然是在控制台中看到“继续”10次。我只是想知道这种语言是否可行(我知道我可以通过for循环实现相同的目标)。例如,使用与上面非常相似的代码在JavaScript中进行操作是微不足道的,但我不能让编译器在C#中配合。我认为失败的原因是无法正确描述“x”(Func<Func<Func...的类型,你需要类似前向声明的东西。

4 个答案:

答案 0 :(得分:5)

为了澄清我之前的评论,C#使用静态类型和“reified”泛型。这意味着编译器会跟踪泛型类型的每个参数化。类型Func<Func<int>>与类型Func<Func<Func<int>>>不同。 C#不支持任何类型的动态递归,更不用说无限参数化了,像Func<Func<...这样的类型的简单构造会涉及无限递归,这种递归会表现为必须跟踪无数种类型。

然而,有一些技巧可以使它工作。它们都以某种方式隐藏了函数的返回类型。其他解决方案通过返回弱类型的后期绑定Delegate对象来完成此操作。但是,还有一种静态类型的解决方案。您所需要做的就是定义自己的非通用delegate对象。

    private delegate InfFunc InfFunc();
    static void Main(string[] args)
    {
        InfFunc f = null;
        int i = 0;
        f = () =>
            {
                if (i > 10) return null;
                i++;
                Debug.WriteLine("Keep going");
                return f;
            };
        var g = f;

        while ((g = g()) != null) ;
        Debug.WriteLine(i);
    }

或者你可以这样做,虽然你的.NET版本不支持DLR:

    static void Main(string[] args)
    {
        Func<dynamic> f = null;
        int i = 0;
        f = () =>
            {
                if (i > 10) return null;
                i++;
                Debug.WriteLine("Keep going");
                return f;
            };
        var g = f;

        while ((g = g()) != null) ;
        Debug.WriteLine(i);
    }

答案 1 :(得分:1)

也许并不完全是你所希望的,但这可以解决问题:

        int i = 0;
        Func<Delegate> x = null;
        x = () =>
        {
            if (i > 10)
                return null;

            Debug.Log("keep going");
            ++i;
            return x;
        };
        Func<Delegate> y = x;
        while ((y = y() as Func<Delegate>) != null) ;

为了解决具有无限序列Func<Func<...的问题,您可以使用Delegate,然后在调用后将其强制转换为Func<Delegate>

答案 2 :(得分:1)

我认为您可以做的最好的事情是返回类型Delegate

int i = 0;
Func<Delegate> f = null;
f = () =>
{
    if (i > 10)
        return null;

    ++i;
    Debug.WriteLine("keep going");

    return f;
};

Delegate y = f;

while ((y = (Delegate)y.DynamicInvoke()) != null)
{

}

答案 3 :(得分:0)

我不确定你要做什么,但是:

int i =0;
Func<Delegate> x = null;
x = () => 
{
    if (i > 10)
        return null;

    ++i;
    Console.WriteLine("keep going");
    return x;
};

var y = x;

while (y() != null) ;