gpt4 book ai didi

c# - 为什么编译器会跳过这个方法?

转载 作者:行者123 更新时间:2023-11-30 22:06:16 25 4
gpt4 key购买 nike

我正在尝试为我的客户提供多种访问排列的方式。我创建了以下执行 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;
}

关于c# - 为什么编译器会跳过这个方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23747616/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com