首页
学习
活动
专区
圈层
工具
发布

实现 IEnumerator<T> GetEnumerator() 和 IEnumerator IEnumerable.GetEnumerator() 的动态生成类

实现 IEnumerator<T> GetEnumerator() 和 IEnumerable.GetEnumerator() 的动态生成类

基础概念

在.NET中,IEnumerable<T>IEnumerable接口用于支持集合的迭代。要实现这些接口,需要提供两个GetEnumerator()方法:

  1. 泛型版本:IEnumerator<T> GetEnumerator()
  2. 非泛型版本:IEnumerator IEnumerable.GetEnumerator()

实现方式

1. 手动实现

代码语言:txt
复制
public class MyCollection<T> : IEnumerable<T>
{
    private readonly List<T> _items = new List<T>();

    // 泛型版本
    public IEnumerator<T> GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    // 非泛型版本(显式实现)
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator(); // 调用泛型版本
    }
}

2. 使用迭代器方法简化

代码语言:txt
复制
public class MyCollection<T> : IEnumerable<T>
{
    private readonly List<T> _items = new List<T>();

    public IEnumerator<T> GetEnumerator()
    {
        foreach (var item in _items)
        {
            yield return item;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

3. 动态生成类(使用Emit API)

代码语言:txt
复制
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

public static class EnumerableGenerator
{
    public static Type CreateEnumerableType(Type itemType)
    {
        var assemblyName = new AssemblyName("DynamicEnumerableAssembly");
        var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
        
        var typeBuilder = moduleBuilder.DefineType(
            $"DynamicEnumerable`1[{itemType.Name}]",
            TypeAttributes.Public,
            typeof(object),
            new[] { typeof(IEnumerable<>).MakeGenericType(itemType), typeof(IEnumerable) });

        // 添加字段存储集合数据
        var fieldBuilder = typeBuilder.DefineField(
            "_items",
            typeof(List<>).MakeGenericType(itemType),
            FieldAttributes.Private);

        // 添加构造函数
        var ctorBuilder = typeBuilder.DefineConstructor(
            MethodAttributes.Public,
            CallingConventions.Standard,
            new[] { typeof(IEnumerable<>).MakeGenericType(itemType) });
        
        var ctorIl = ctorBuilder.GetILGenerator();
        ctorIl.Emit(OpCodes.Ldarg_0);
        ctorIl.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
        ctorIl.Emit(OpCodes.Ldarg_0);
        ctorIl.Emit(OpCodes.Ldarg_1);
        ctorIl.Emit(OpCodes.Newobj, typeof(List<>).MakeGenericType(itemType).GetConstructor(new[] { typeof(IEnumerable<>).MakeGenericType(itemType) }));
        ctorIl.Emit(OpCodes.Stfld, fieldBuilder);
        ctorIl.Emit(OpCodes.Ret);

        // 实现泛型 GetEnumerator
        var methodBuilder = typeBuilder.DefineMethod(
            "GetEnumerator",
            MethodAttributes.Public | MethodAttributes.Virtual,
            typeof(IEnumerator<>).MakeGenericType(itemType),
            Type.EmptyTypes);
        
        var methodIl = methodBuilder.GetILGenerator();
        methodIl.Emit(OpCodes.Ldarg_0);
        methodIl.Emit(OpCodes.Ldfld, fieldBuilder);
        methodIl.Emit(OpCodes.Callvirt, typeof(List<>).MakeGenericType(itemType).GetMethod("GetEnumerator"));
        methodIl.Emit(OpCodes.Ret);

        // 实现接口的泛型 GetEnumerator
        typeBuilder.DefineMethodOverride(
            methodBuilder,
            typeof(IEnumerable<>).MakeGenericType(itemType).GetMethod("GetEnumerator"));

        // 实现非泛型 GetEnumerator
        var nonGenericMethodBuilder = typeBuilder.DefineMethod(
            "System.Collections.IEnumerable.GetEnumerator",
            MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Final,
            typeof(IEnumerator),
            Type.EmptyTypes);
        
        var nonGenericMethodIl = nonGenericMethodBuilder.GetILGenerator();
        nonGenericMethodIl.Emit(OpCodes.Ldarg_0);
        nonGenericMethodIl.Emit(OpCodes.Call, methodBuilder);
        nonGenericMethodIl.Emit(OpCodes.Ret);

        // 实现接口的非泛型 GetEnumerator
        typeBuilder.DefineMethodOverride(
            nonGenericMethodBuilder,
            typeof(IEnumerable).GetMethod("GetEnumerator"));

        return typeBuilder.CreateType();
    }
}

使用动态生成的类

代码语言:txt
复制
// 创建动态类型
var dynamicType = EnumerableGenerator.CreateEnumerableType(typeof(string));

// 创建实例
var instance = Activator.CreateInstance(dynamicType, new object[] { new List<string> { "a", "b", "c" } });

// 使用foreach迭代
foreach (var item in (IEnumerable)instance)
{
    Console.WriteLine(item);
}

优势

  1. 类型安全:泛型版本提供类型安全的迭代
  2. 兼容性:非泛型版本确保与旧代码兼容
  3. 灵活性:动态生成可以在运行时创建特定类型的可枚举类
  4. 性能:直接使用集合的枚举器,避免装箱拆箱

应用场景

  1. 需要动态生成可枚举类型的框架
  2. 需要运行时创建特定集合类型的场景
  3. 需要实现自定义集合类但不想手动编写样板代码
  4. 需要为反射生成的类型添加枚举支持

常见问题与解决方案

问题1:为什么需要实现两个GetEnumerator方法?

原因:.NET 1.0只有非泛型IEnumerable,.NET 2.0引入了泛型IEnumerable<T>。为了向后兼容,需要同时实现两个版本。

解决方案:总是先实现泛型版本,然后让非泛型版本调用泛型版本。

问题2:动态生成的类型性能如何?

原因:首次生成类型会有开销,但之后使用与手动编写的类性能相同。

解决方案:考虑缓存生成的类型以减少运行时开销。

问题3:如何处理自定义迭代逻辑?

原因:动态生成简单委托给集合的枚举器,但有时需要自定义逻辑。

解决方案:可以在生成代码中添加自定义迭代逻辑,或使用迭代器方法(yield return)模式。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

没有搜到相关的文章

领券