Как отфильтровать все варианты универсального типа с помощью OfType

#c# #linq #generics #filter #oftype

#c# #linq #общие #Фильтр #oftype

Вопрос:

Я хочу фильтровать объекты в List<ISeries> , используя их тип, используя OfType<> .Моя проблема в том, что некоторые объекты имеют общий тип интерфейса, но у них нет собственного общего унаследованного интерфейса.

У меня есть следующие определения:

 public interface ISeries
public interface ITraceSeries<T> : ISeries
public interface ITimedSeries : ISeries
//and some more...
  

Мой список содержит все виды ISeries , но теперь я хочу получить только ITraceSeries объекты, независимо от их фактически определенного параметра универсального типа, вот так:

 var filteredList = myList.OfType<ITraceSeries<?>>(); //invalid argument!
  

Как я могу это сделать?

Неблагоприятным решением было бы ввести тип, ITraceSeries который наследуется от ISeries :

 public interface ITraceSeries<T> : ITraceSeries
  

Затем используйте ITraceSeries в качестве фильтра. Но это на самом деле не добавляет новой информации, а только усложняет цепочку наследования.

Мне кажется, это обычная проблема, но я не нашел полезной информации на SO или в Интернете. Спасибо за помощь!

Комментарии:

1. Подумайте о том, каким должен быть возвращаемый тип myList.OfType .

2. Это должно быть IEnumerable<iSeries> . Но это хороший момент, как сообщить об этом методу OfType<> !?

3. Возвращаемый тип OfType такой же, как у параметра type.

4. @Martinho Nit: он возвращает IEnumerable параметра типа

Ответ №1:

Вы можете использовать отражение для достижения этого:

 var filteredList = myList.Where(
    x => x.GetType()
          .GetInterfaces()
          .Any(i => i.IsGenericType amp;amp; (i.GetGenericTypeDefinition() == typeof(ITraceSeries<>))));
  

Комментарии:

1. Отличный материал! Однако я подумал, что мог бы уменьшить сложность… Теперь моя сложность скрыта в удаленном пространстве, а не в структуре наследования! 🙂

2. Можете ли вы сказать мне, какой typeof(ITraceSeries<>) на самом деле возвращает как type? Насколько я знаю, универсальные типизированные классы не имеют общего базового класса. (Это было моим источником проблем в первую очередь)

3. @Marcel: typeof(ITraceSeries<>) возвращает открытый универсальный тип для ITraceSeries<T> . Вы не можете объявлять объекты этого типа, но вы можете использовать это для создания замкнутых типов, подобных ITraceSeries<string> .

4. @Martinho: Просто для придирчивости, технически typeof<I<>> лучше охарактеризовать как несвязанный универсальный тип. Является ли тип открытым или закрытым, зависит от того, есть ли в нем какие-либо незамещенные параметры типа; например, I<T[]> связан, но открыт. I<int[]> связан и закрыт, I<> не связан.

Ответ №2:

 from s in series
where s.GetType().GetGenericTypeDefinition()==typeof(ITraceSeries<>)
select s;
  

Комментарии:

1. Хорошая идея, но это не будет работать точно так, потому что typeof(ITraceSeries<string>) != typeof(ITraceSeries<>) . Исправлено.

2. 🙂 Большая часть ответов — это просто идеи — направление к правильному решению. Спасибо за исправление.

3. @Martinho: Это все равно не сработает, потому что GetType вернет конкретный тип среды выполнения, а этого типа никогда не будет ITraceSeries<something> , это будет конкретная реализация ITraceSeries<something> . Смотрите мой ответ для решения, которое, надеюсь, должно соответствовать требованиям OP.