如何创建动态类型的C#迭代器块?

时间:2010-11-23 05:42:10

标签: c# generics iterator

我正在做一个AOP类的层,我想为泛型集合返回一个迭代器块(即“IEnumerable”之类的东西)。但是,动态发现类型T.我可以找到该类型并将其作为“类型”变量在本地使用但是如何超越它并为该动态发现的类型返回迭代器块?

我想要的是这样的东西(尽管我可以在传统的C#中表达它):

public IEnumerator<runtimeDiscoveredType>  EntryIteratorBlock(Type desiredElementType)
{
     // One can assume that desireElementType is the same as (or convertible to) runtimeDiscoveredType
     TypeConverter tc = new TypeConverter()
     var actualItem = ....; // some code goes here to pick up the actual item from
     ...                    // some collection.

     if (ChooseThisItem(actualItem))
         yield return tc.ConvertTo(actualItem, desiredElementType);
     else
         yield break;
}

然后我想返回EntryIteratorBlock,以便我可以动态地遍历集合。 (集合中的元素加载很昂贵,所以我想懒得加载它们。)

2 个答案:

答案 0 :(得分:3)

编译器必须计算对EntryIteratorBlock的返回类型的调用,它不能用于运行时类型。 IEnumerator<runtimeDiscoveredType>是一个矛盾。

您在编译时获得的最多信息是序列将包含对象:

public IEnumerator<object> EntryIteratorBlock(Type desiredElementType)
{
    // ...
}

或者,如果序列中的项目共享一个共同类型:

public IEnumerator<BaseElementType> EntryIteratorBlock(Type desiredElementType)
{
    // ...
}

如果你发布一些关于你试图用迭代器解决的问题的信息,我们或许能够在更基础的层面上提供帮助。

答案 1 :(得分:0)

虽然目前尚不清楚这是否正确,但这是一种有效的方法:

class Program
{
    // this method is not called directly
    // but it is public so it is found by reflection
    public static IEnumerable<U> EntryIteratorBlock<T, U>(
        IEnumerable<T> source, Func<object, bool> selector)
    {
        TypeConverter tc = new TypeConverter();
        foreach (T item in source)
            if (selector(item))
                yield return (U)tc.ConvertTo(item, typeof(U));
    }

    static IEnumerable CreateIterator(
        // these are the type parameters of the iterator block to create
        Type sourceType, Type destType,
        // these are the parameters to the iterator block being created
        IEnumerable source, Func<object, bool> selector)
    {
        return (IEnumerable) typeof(Program)
            .GetMethod("EntryIteratorBlock")
            .MakeGenericMethod(sourceType, destType)
            .Invoke(null, new object[] { source, selector });
    }

    static void Main(string[] args)
    {
        // sample code prints "e o w o"
        foreach (var i in CreateIterator(typeof(char), typeof(string),
                          "Hello, world", c => ((char)c & 1) == 1))
            Console.WriteLine(i);
    }
}