我正试图为访问排列提供我的客户多种方式。我创建了下面的代码,在每个探视执行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);
}
我的直觉是,编译器不开心,我利用递归的返回值是不。但是,这只是一种预感。先谢谢你。
我的猜测是,它确实* *工作,它只是不右看看在调试器中,因为''yield'创建return'的'IEnumerable'的懒惰执行。尝试在您生成的IEnumerable上调用'ToList'来强制执行,看看会发生什么。另请参阅http://brianreiter.org/2011/01/14/ienumerable-is-lazy-and-thats-cool/ –
我不想转换ToList,因为可能有大量的项目和溢出RAM。 – sapbucket
你只需要做足够长的时间就可以证明它确实有效。 :)你不必永远离开ToList()。调用ToList()将允许您在调试器中查看整个迭代。 –