2010-11-23 2 views
1

Я делаю слой типа AOP, и я хотел бы вернуть блок итератора для общей коллекции (например, что-то вроде «IEnumerable»). Однако тип T динамически обнаруживается. Я могу найти этот тип и иметь его локально как переменную «Тип», но как я могу выйти за рамки этого и вернуть блок итератора для этого динамически обнаруженного типа?Как создать динамически типизированный блок итератора 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; 
} 

Я хотел бы затем вернуть EntryIteratorBlock, так что я могу динамически переборе коллекции. (Элементы в коллекции дороги для загрузки, и поэтому я хочу загрузить их лениво.)

+0

Я согласен с Питером; более конкретный пример упростит, если я напишу о том, что вы пытаетесь сделать. – Gabe 2010-11-23 07:00:05

ответ

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

Да, это то, что я искал. Спасибо. – Tevya 2010-11-23 16:48:39

3

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

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

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

Или, если элементы в доле последовательностях общего типа:

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

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

Смежные вопросы