Ошибка итератора (более вероятно) очень тонкого поведения? - PullRequest
1 голос
/ 10 августа 2010

Моя проблема требует 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();  
}  

Заранее благодарен за помощь
Филипп

Ответы [ 2 ]

5 голосов
/ 10 августа 2010

Ваш 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;
        }
    }
}
3 голосов
/ 10 августа 2010

Как говорит lasseespeholt, проблема в том, что вы неоднократно получаете ссылки на один и тот же массив, а затем изменяете этот массив.

Вызов ToList() будет выполнять итерацию по всему итератору, поэтому вы в конечном итоге получитесо списком одних и тех же ссылок несколько раз, и к тому времени, когда вы проверите содержимое, все это будет равно -1.

Одно простое исправление - изменить выражение возврата одометра на:

yield return result.ToArray();

Это клонирует массив в том месте, где вы его выдаете, поэтому список будет иметь различных ссылок на массивы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...