【问题标题】:How do I create a dynamically typed C# iterator block?如何创建动态类型的 C# 迭代器块?
【发布时间】:2011-05-14 06:43:06
【问题描述】:

我正在做一个 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 以便我可以动态地遍历集合。 (集合中的元素加载起来很昂贵,所以我想懒惰地加载它们。)

【问题讨论】:

  • 我同意彼得的观点;一个更具体的例子会让你更容易判断我是否在写你正在尝试做的事情。

标签: c# generics iterator


【解决方案1】:

编译器必须计算出对EntryIteratorBlock 的调用的返回类型,而对于运行时类型它无法做到这一点。 IEnumerator&lt;runtimeDiscoveredType&gt; 用词自相矛盾。

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

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

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

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

如果您发布一些有关您尝试使用迭代器解决的问题的信息,我们或许能够提供更基础的帮助。

【讨论】:

    【解决方案2】:

    虽然尚不清楚这是否是正确的方法,但这是一种可行的方法:

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

    【讨论】:

    • 是的,这就是我要找的。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 2014-03-21
    • 2023-03-15
    • 2012-05-10
    • 2016-09-23
    • 1970-01-01
    • 2023-03-09
    相关资源
    最近更新 更多