将枚举器(不可枚举)类型映射到另一种类型的枚举器
Map enumerator (not enumerable) type to an enumerator of another type
如何将 IEnumerator<KeyValuePair<TKey, TValue>>
转换为包含键值对中的键的 IEnumerator<TKey>
?
更一般地说,如果存在从 TSource
到 TTarget
的转换,我如何将 IEnumerator<TSource>
转换为 IEnumerator<TTarget>
?
请注意,此问题并非寻求有关如何枚举枚举数(使用 MoveNext
和 Current
)或如何将枚举数转换为可枚举数的信息(参见 this discussion), or how to transform an enumerable to an enumerator (just call GetEnumerator()
on the IEnumerable<T>
), or how to map an enumerable to another type (see this discussion ).
我已经提供了我自己提出的答案作为答案,但当然我很高兴听到其他方法。
我比较喜欢的做法如下。 (也可以将其定义为 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();
}
}
这是一种方法,使用 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
方法是私有的。在一个publicAPI中,客户端希望一个enumerable可以多次使用,但是这里的enumerable只能使用一次。但是,由于 Reset 的行为是未定义的,因此 Enumerator 预计只会被使用一次,所以这就实现了它的目标。
如何将 IEnumerator<KeyValuePair<TKey, TValue>>
转换为包含键值对中的键的 IEnumerator<TKey>
?
更一般地说,如果存在从 TSource
到 TTarget
的转换,我如何将 IEnumerator<TSource>
转换为 IEnumerator<TTarget>
?
请注意,此问题并非寻求有关如何枚举枚举数(使用 MoveNext
和 Current
)或如何将枚举数转换为可枚举数的信息(参见 this discussion), or how to transform an enumerable to an enumerator (just call GetEnumerator()
on the IEnumerable<T>
), or how to map an enumerable to another type (see this discussion ).
我已经提供了我自己提出的答案作为答案,但当然我很高兴听到其他方法。
我比较喜欢的做法如下。 (也可以将其定义为 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();
}
}
这是一种方法,使用 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
方法是私有的。在一个publicAPI中,客户端希望一个enumerable可以多次使用,但是这里的enumerable只能使用一次。但是,由于 Reset 的行为是未定义的,因此 Enumerator 预计只会被使用一次,所以这就实现了它的目标。