简体   繁体   English

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

[英]How do I create a dynamically typed C# iterator block?

I am doing an AOP kind of layer and I would like to return an iterator block for a generic collection (ie something like "IEnumerable"). 我正在做一种AOP层,我想为通用集合返回一个迭代器块(即类似“ IEnumerable”的东西)。 However, the type T is dynamically discovered. 但是,类型T是动态发现的。 I can find that type and have it locally as a "Type" variable but how do I go beyond that and return an iterator block for that dynamically-discovered type? 我可以找到该类型,并在本地将其作为“类型”变量,但是如何超越该类型并为该动态发现的类型返回迭代器块?

What I want is something like this (as close as I can express it in conventional C#): 我想要的是这样的东西(就像我在常规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;
}

I would like to then return the EntryIteratorBlock so that I can dynamically walk through the collection. 然后,我想返回EntryIteratorBlock,以便我可以动态遍历集合。 (The elements in the collection are expensive to load and so I want to load them lazily.) (集合中的元素加载起来很昂贵,因此我想延迟加载它们。)

The compiler has to work out the return type of calls to EntryIteratorBlock , which it cannot do with a runtime type. 编译器必须计算出对EntryIteratorBlock的返回类型,而对于运行时类型则不能。 IEnumerator<runtimeDiscoveredType> is a contradiction in terms. IEnumerator<runtimeDiscoveredType>在术语上是矛盾的。

The most information you have at compile-time is that the sequence will contain objects: 您在编译时获得的最多信息是该序列将包含对象:

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

Or, if the items in the sequence share a common type: 或者,如果序列中的项目具有共同的类型:

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

If you post some information about the problem you are trying to solve with the iterator, we might be able to offer help at a more fundamental level. 如果您发布有关您要使用迭代器解决的问题的信息,我们也许可以在更基本的层面上提供帮助。

Although it's not clear that this is the right way to do this, here's a way that works: 尽管目前尚不清楚这是否是正确的方法,但这是一种可行的方法:

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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM