Когда я должен использовать IEnumerator для цикличного выполнения в c#?

Вот функция, которую вы можете использовать для дедуплирования строки, как вы описали. Обратите внимание, что это не будет сортировать дедуплированную строку, поэтому, если ваш был чем-то вроде «4,2,5,1,3,2,2», результат был бы «4,2,5,1,3». Вы не указали, что вам нужно было его отсортировать, поэтому я не включил эту функциональность. Обратите внимание, что функция использует , в качестве разделителя по умолчанию, если не указана, но вы можете указать разделитель, если вы выберете.

Function DeDupeString(ByVal sInput As String, Optional ByVal sDelimiter As String = ",") As String

    Dim varSection As Variant
    Dim sTemp As String

    For Each varSection In Split(sInput, sDelimiter)
        If InStr(1, sDelimiter & sTemp & sDelimiter, sDelimiter & varSection & sDelimiter, vbTextCompare) = 0 Then
            sTemp = sTemp & sDelimiter & varSection
        End If
    Next varSection

    DeDupeString = Mid(sTemp, Len(sDelimiter) + 1)

End Function

Вот несколько примеров того, как вы это назвали:

Sub tgr()

    MsgBox DeDupeString("1,2,3,4,5,2,2")    '--> "1,2,3,4,5"

    Dim myString As String
    myString = DeDupeString("4-2-5-1-3-2-2", "-")
    MsgBox myString     '--> "4-2-5-1-3"

End Sub
24
задан lomaxx 19 January 2009 в 03:19
поделиться

4 ответа

Во-первых, обратите внимание, что одна большая разница в Вашем примере (между foreach и GetEnumerator) - то, что foreach гарантии для вызова Dispose() на итераторе, если итератор IDisposable. Это важно для многих итераторов (который мог бы использовать внешний канал данных, например).

На самом деле, существуют случаи, где foreach не так полезно, как мы хотели бы.

Первый, существует "первый объект" случай, обсудил здесь (foreach / обнаружение первого повторения) .

, Но больше; при попытке писать пропавшим без вести Zip метод для сшивания двух счетных последовательностей вместе (или SequenceEqual метод), Вы находите, что можно' использовать foreach на обеих последовательностях, так как это выполнило бы перекрестное объединение. Необходимо использовать итератор непосредственно для одного из них:

static IEnumerable<T> Zip<T>(this IEnumerable<T> left,
    IEnumerable<T> right)
{
    using (var iter = right.GetEnumerator())
    {
        // consume everything in the first sequence
        foreach (var item in left)
        {
            yield return item;

            // and add an item from the second sequnce each time (if we can)
            if (iter.MoveNext())
            {
                yield return iter.Current;
            }
        }
        // any remaining items in the second sequence
        while (iter.MoveNext())
        {
            yield return iter.Current;
        }                
    }            
}

static bool SequenceEqual<T>(this IEnumerable<T> left,
    IEnumerable<T> right)
{
    var comparer = EqualityComparer<T>.Default;

    using (var iter = right.GetEnumerator())
    {
        foreach (var item in left)
        {
            if (!iter.MoveNext()) return false; // first is longer
            if (!comparer.Equals(item, iter.Current))
                return false; // item different
        }
        if (iter.MoveNext()) return false; // second is longer
    }
    return true; // same length, all equal            
}
31
ответ дан Community 16 October 2019 в 08:04
поделиться

Согласно спецификация языка C#:

А foreach оператор формы

foreach (V v in x) embedded-statement

тогда расширен до:

{
    E e = ((C)(x)).GetEnumerator();
    try {
            V v;
            while (e.MoveNext()) {
                    v = (V)(T)e.Current;
                    embedded-statement
            }
    }
    finally {
            ... // Dispose e
    }
}

сущность Ваших двух примеров является тем же, но существуют некоторые важные различия, прежде всего try / finally.

19
ответ дан Jay Bazuzi 16 October 2019 в 08:04
поделиться

В C#, foreach делает точно то же самое как эти IEnumerator код, который Вы отправили выше. Эти foreach конструкция обеспечивается для облегчения для программиста. Я полагаю, что IL, сгенерированный в обоих случаях, является тем же/подобным.

12
ответ дан Jay Bazuzi 16 October 2019 в 08:04
поделиться

Я использовал его иногда, когда первое повторение делает что-то другое от других.

, Например, если Вы хотите распечатать участников, чтобы подключиться с консоли и разделить результаты с методической точностью, можно записать.

using (IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator()) {
    if (classEnum.MoveNext())
        Console.WriteLine(classesEnum.Current);
    while (classesEnum.MoveNext()) {
        Console.WriteLine("-----------------");
        Console.WriteLine(classesEnum.Current);
    }
}

Тогда результат

myClass 1
-----------------
myClass 2
-----------------
myClass 3

, И другая ситуация состоит в том, когда я выполняю итерации 2 перечислителей вместе.

using (IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator()) {
    using (IEnumerator<MyClass> classesEnum2 = myClasses2.GetEnumerator()) {
        while (classesEnum.MoveNext() && classEnum2.MoveNext())
            Console.WriteLine("{0}, {1}", classesEnum.Current, classesEnum2.Current);
    }
}

результат

myClass 1, myClass A
myClass 2, myClass B
myClass 3, myClass C

Используя перечислитель позволяет Вам делать более гибкий на Вашем повторении. Но в большей части случая, можно использовать foreach

4
ответ дан Chaowlert Chaisrichalermpol 16 October 2019 в 08:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: