我的问题需要3个(不太长的功能)来重现(VS2010 / .NET 4)
在第一种情况下,我的IEnumerable未被评估(通过ToList()方法)
我不明白为什么......
//主程序
private void ButtonTest_Click(object sender, RoutedEventArgs args)
{
int[] indexes = new int[] { 2, 2, 2, 2, 2, 2 };
var query = Odometer(indexes);
// 1) Iterator not evaluated ???
var temp = query.ToList();
MessageBox.Show(AsString(temp[3]));
// 2) OK in this case
int count = 0;
foreach (int[] item in query)
{
count++;
if (count == 3)
MessageBox.Show(AsString(item));
}
}
/// <summary>
/// Generate all tuples between 0 and indexes[i]-1
/// Ex :
/// Odometer(new int[]{2, 3}); // (0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2)
/// </summary>
/// <param name="indexes"></param>
/// <returns></returns>
public static IEnumerable<int[]> Odometer(int[] indexes)
{
int[] result = new int[indexes.Length];
for (int i = 0; i < indexes.Length; i++)
result[i] = -1;
int ptr = 0;
while (ptr >= 0)
{
while (ptr < indexes.Length)
{
result[ptr++]++;
continue;
}
ptr--;
while (result[ptr] < indexes[ptr])
{
yield return result;
result[ptr]++;
}
result[ptr]--;
while (result[ptr] == indexes[ptr] - 1)
{
result[ptr] = -1;
ptr--;
if (ptr < 0)
break;
}
}
}
/// <summary>
/// Format an IList of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array"></param>
/// <returns></returns>
private static string AsString<T>(IList<T> array)
{
StringBuilder builder = new StringBuilder();
foreach (T item in array)
builder.AppendFormat("{0}, ", item);
if (builder.Length >= 2)
builder.Length -= 2;
return builder.ToString();
}
提前感谢您的帮助 菲利普
答案 0 :(得分:5)
您的IEnumerable在以下时间运行:
var temp = query.ToList();
我在里程表上做了一个断点,果然它破了。它包含很多-1的列表。也许你需要更好的里程表方法?
编辑:问题是你总是会返回同一个数组。所以它总是具有相同的价值。您应该阅读.Net / C#中有关引用的内容。此外,该方法只需要长度,所以只发送长度。
public static IEnumerable<int[]> Odometer(int[] indexes)
{
int[] result = new int[indexes.Length];
for (int i = 0; i < indexes.Length; i++)
result[i] = -1;
int ptr = 0;
while (ptr >= 0)
{
while (ptr < indexes.Length)
{
result[ptr++]++;
continue;
}
ptr--;
while (result[ptr] < indexes[ptr])
{
//HERE
//Clones the array so you are returning a new array - thanks Jon, for improvement on the Array.Copy code.
yield return result.ToArray();
result[ptr]++;
}
result[ptr]--;
while (result[ptr] == indexes[ptr] - 1)
{
result[ptr] = -1;
ptr--;
if (ptr < 0)
break;
}
}
}
答案 1 :(得分:3)
正如lasseespeholt所说,问题是你反复产生对同一个数组的引用,然后改变那个数组。
调用ToList()
将遍历整个迭代器,因此您将多次查看相同引用的列表,并且当您检查内容时,它将全部为-1。
一个简单的解决方法是将里程表的收益率报表更改为:
yield return result.ToArray();
这将在您生成数组的位置克隆数组,因此列表将包含不同的数组引用。