C#泛型与非泛型枚举器的比较

3

一个新手问题。

C#中的数组返回一个非泛型(传统)IEnumerator。其他集合可以提供任一类型。

通常来说,如果可用,使用泛型枚举器是否更好,例如出于类型安全的原因?是否有时非泛型选项更可取?


请记住,在C# 1中有数组,而泛型直到C# 2才出现,因此对于数组(以及ArrayListHashTable等),要返回它们可能会很棘手... - AakashM
2个回答

2
通常情况下,使用通用枚举是非常可取的,因为正如您在问题中提到的那样,它具有类型安全性。
如果您只存储对象集合,则可以选择非通用枚举。因此,您可以编写IEnumerable而不是IEnumerable,并在迭代过程中确定实际的对象类型(如果需要的话,但通常是需要的)。

1

foreach 实际上并不总是使用 IEnumerable[<T>] / IEnumerator[<T>] API。首先,它实际上并不是必需的:所有需要的是一个返回具有 bool MoveNext()Current {get;}某些东西GetEnumerator() 方法 - 例如,List<T> 具有自定义迭代器。这种方法在 .NET 1.1 中也很常见,以避免装箱,通过优先考虑自定义迭代器。

然而,在数组的情况下,它可能更加有趣;请考虑:

    static void Main()
    {
        foreach(var i in GetData()) Console.WriteLine(i);
    }
    static int[] GetData()
    {
        int[] data = { 1, 2, 3, 4, 5 };
        return data;
    }

在这里,Main被编译为(//注释是我的):
.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] int32[] CS$6$0000,
        [2] int32 CS$7$0001)

    // int[] arr = GetData()
    L_0000: call int32[] ConsoleApplication7.Program::GetData()
    L_0005: stloc.1

    // int j = 0
    L_0006: ldc.i4.0 
    L_0007: stloc.2

    // run end-condition of for loop first...
    L_0008: br.s L_0018

    // i = arr[j]
    L_000a: ldloc.1 
    L_000b: ldloc.2 
    L_000c: ldelem.i4          
    L_000d: stloc.0

    // Console.WriteLine(i);
    L_000e: ldloc.0 
    L_000f: call void [mscorlib]System.Console::WriteLine(int32)

    // j++
    L_0014: ldloc.2 
    L_0015: ldc.i4.1 
    L_0016: add 
    L_0017: stloc.2

    // j < arr.Length
    L_0018: ldloc.2 
    L_0019: ldloc.1 
    L_001a: ldlen 
    L_001b: conv.i4
    L_001c: blt.s L_000a

    L_001e: ret 
}

这段代码完全没有使用枚举器 API,而是将其实现为一个 for 循环。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接