#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.