Сопоставить тип перечислителя (не перечисляемый) с перечислителем другого типа - PullRequest
0 голосов
/ 05 января 2019

Как я могу преобразовать IEnumerator<KeyValuePair<TKey, TValue>> в IEnumerator<TKey>, содержащий ключ из пары ключ-значение?

В общем, как я могу преобразовать IEnumerator<TSource> в IEnumerator<TTarget>, если есть преобразование из TSource в TTarget?

Обратите внимание, что этот вопрос не ищет информацию о том, как перечислить перечислитель (используйте MoveNext и Current), или как преобразовать перечислитель в перечислимый (см. это обсуждение ), или как преобразовать перечислимое в перечислитель (просто вызовите GetEnumerator() на IEnumerable<T>) или как сопоставить перечислимое с другим типом (см. это обсуждение ).

Я предоставил свои собственные предлагаемые ответы в качестве ответов, но, конечно, я рад услышать о других подходах.

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Вот один из подходов, использующий static class:

public static class TransformEnumerator2<TSource, TTarget>
{
    public static IEnumerator<TTarget> GetEnumerator(IEnumerator<TSource> source, Func<TSource, TTarget> transformFunc)
    {
        return (IEnumerator<TTarget>)GetEnumerable(source, transformFunc);
    }

    private static IEnumerable<TTarget> GetEnumerable(IEnumerator<TSource> source, Func<TSource, TTarget> transformFunc)
    {
        while (source.MoveNext())
            yield return transformFunc(source.Current);
    }
}

Обратите внимание, что метод GetEnumerable является закрытым. В общедоступном API клиент ожидает, что он сможет использовать перечисляемое множество раз, но перечисляемое здесь может использоваться только один раз. Однако ожидается, что Enumerator будет использоваться только один раз, поскольку поведение Reset не определено, поэтому это достигает своей цели.

0 голосов
/ 05 января 2019

Подход, который мне нравится больше, заключается в следующем. (Можно также определить его как struct вместо class, например, чтобы уменьшить выделение кучи.)

public class TransformEnumerator<TSource, TTarget> : IEnumerator<TTarget>
{
    IEnumerator<TSource> SourceEnumerator;
    Func<TSource, TTarget> TransformFunc;

    public TransformEnumerator(IEnumerator<TSource> sourceEnumerator, Func<TSource, TTarget> transformFunc)
    {
        SourceEnumerator = sourceEnumerator;
        TransformFunc = transformFunc;
    }

    public TTarget Current => TransformFunc(SourceEnumerator.Current);

    object IEnumerator.Current => TransformFunc(SourceEnumerator.Current);

    public void Dispose()
    {
        SourceEnumerator.Dispose();
    }

    public bool MoveNext()
    {
        return SourceEnumerator.MoveNext();
    }

    public void Reset()
    {
        SourceEnumerator.Reset();
    }
}
...