簡體   English   中英

為什么編譯器會跳過此方法?

[英]Why does the compiler skip this method?

我正在嘗試為客戶提供多種訪問排列的方式。 我創建了以下代碼,每次執行時都執行Action<T[]> output

    public void Permute<T>(T[][] sets, Action<T[]> output)
    {
        Permute(sets, 0, new T[sets.Length], output);
    }

    private void Permute<T>(T[][] sets, int set, T[] permutation, Action<T[]> output)
    {
        for (int i = 0; i < sets[set].Length; ++i)
        {
            permutation[set] = sets[set][i];

            if (set < (sets.Length - 1))
                Permute(sets, set + 1, permutation, output);
            else
                output(permutation);
        }
    }

它起作用了,所以我轉到了訪問排列的下一種方法,即使用IEnumerable<int[]>yield return模式。 這是我的實現:

    public IEnumerable<int[]> Permute(int[][] sets)
    {
       return  Permute(sets, 0, new int[sets.Length]); // <--skips this
    }

    private IEnumerable<int[]> Permute(int[][] sets, int set, int[] permutation)
    {
        for (int i = 0; i < sets[set].Length; ++i)
        {
            permutation[set] = sets[set][i];

            if (set < (sets.Length - 1))
                Permute(sets, set + 1, permutation);
            else
                yield return permutation;
        }
    }

但這不起作用。 編譯器會跳過指定的代碼行,而不會嘗試執行它。

有人可以向我解釋如何修改所提供的代碼,以使其啟用IEnumerable<int[]>yield return模式嗎?

這是使用以下代碼進行測試的客戶端代碼:(我正在使用nunit)

    [Test]
    public void PermuteThreeDifferentSetsUsingTheirIndexValues()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var indexSets = new[]
                            {
                                new[] {0, 1, 2},
                                new[] {0, 1, 2},
                                new[] {0, 1, 2},
                            };

        var results = _generator.Permute(indexSets);

        foreach (var result in results)
        {
            _permCounter++;
            Console.Write(result[0]);
            Console.Write(" ");
            Console.Write(result[1]);
            Console.Write(" ");
            Console.Write(result[2]);
            Console.WriteLine();
        }
        stopwatch.Stop();

        Console.WriteLine("Permutation Visitor Elapsed Ticks: " + stopwatch.ElapsedTicks);

        Assert.AreEqual(27, _permCounter);
    }

我的直覺是,編譯器對我使用遞歸的返回值不滿意。 但是,這只是預感。 先感謝您。

那就是它的設計工作方式,以及大量的代碼可以自由使用: IEnumerable<T>實現被允許是懶惰的。 Permute不會直接進行任何工作:它返回一個對象,一旦您開始對其進行迭代,便會開始執行某些工作,並且僅足以確定結果的第一個。 當循環然后請求下一個項目時,您的函數將繼續,但僅持續到可以確定第二個結果為止。

這在諸如enumerable.Where(some predicate).First()代碼中非常有用,因為一旦找到第一個結果,它就避免評估謂詞。

在最外部的函數中,對_generator.Permute(indexSets)的結果進行迭代,但是在該函數中,您調用Permute(sets, set + 1, permutation)並丟棄結果(如您在問題中所指出的) 。 由於您不使用該遞歸調用的結果,因此效果就好像該遞歸調用永遠不會發生。

一般而言,當您要在迭代器函數中遞歸調用自己時,您需要yield return每個結果。 一個愚蠢的例子:

IEnumerable<int> f(int n) {
    if (n > 0)
        foreach (var i in f(n - 1))
            yield return i;
    for (int i = 0; i != n; i++)
        yield return i;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM