Как мне создать динамически типизированный блок итератора C #? - PullRequest
1 голос
/ 23 ноября 2010

Я делаю слой типа 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 ]

3 голосов
/ 23 ноября 2010

Компилятор должен определить тип возвращаемых вызовов для EntryIteratorBlock, чего он не может сделать с типом среды выполнения.IEnumerator<runtimeDiscoveredType> является противоречием в терминах.

Наибольшая информация, которую вы имеете во время компиляции, состоит в том, что последовательность будет содержать объекты:

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

Или, если элементы в последовательности разделяютраспространенный тип:

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

Если вы опубликуете некоторую информацию о проблеме, которую вы пытаетесь решить с помощью итератора, мы можем предложить помощь на более фундаментальном уровне.

0 голосов
/ 23 ноября 2010

Хотя не ясно, что это правильный способ сделать это, вот способ, который работает:

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