Некоторая путаница с LINQ

Некоторая справочная информация;

  • LanguageResource - это базовый класс
  • LanguageTranslatorResource и LanguageEditorResource наследуются от LanguageResource
  • LanguageEditorResource определяет свойство IsDirty
  • LanguageResourceCollection - это коллекция LanguageResource
  • LanguageResourceCollection внутренне содержит LanguageResources в Dictionary<string, LanguageResource> _dict
  • LanguageResourceCollection.GetEnumerator () возвращает _dict.Values.GetEnumerator()

У меня есть LanguageResourceCollection _resources, который содержит только объекты LanguageEditorResource, и я хочу использовать LINQ для перечисления тех, которые являются грязными, поэтому я попробовал следующее. Мои конкретные вопросы выделены жирным шрифтом.

  1. _resources.Where(r => (r as LanguageEditorResource).IsDirty)

    ни где другие методы LINQ не отображаются в Intellisense, но я все равно кодирую его, и мне говорят, что «LanguageResourceCollection не содержит определения для 'Where' и никакого метода расширения ...».

    Почему способ, которым LanguageResourceCollection реализует IEnumerable, не позволяет ему поддерживать LINQ?

  2. Если я изменю запрос на

    (_resources as IEnumerable<LanguageEditorResource>).Where(r => r.IsDirty)

    Intellisense отображает методы LINQ и компилирует решение. Но во время выполнения я получаю ArgumentNullException «Значение не может быть нулевым. Имя параметра: источник» .

    Это проблема в моем коде LINQ?
    Это проблема с общим дизайном классов?
    Как я могу разобраться в том, что генерирует LINQ, чтобы попытаться понять, в чем проблема?

Моя цель с этим вопросом заключается не в том, чтобы получить решение конкретной проблемы, поскольку мне придется решать ее сейчас, используя другие (не LINQ) средства, а в том, чтобы попытаться улучшить свое понимание LINQ и узнать, как я могу улучшить дизайн. моих классов, чтобы лучше работать с LINQ.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
2 644
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Похоже, ваша коллекция реализует IEnumerable, а не IEnumerable<T>, поэтому вам нужно:

_resources.Cast<LanguageEditorResource>().Where(r => r.IsDirty)

Обратите внимание, что Enumerable.Where определен на IEnumerable<T>, а не на IEnumerable - если у вас неуниверсальный тип, вам нужно использовать Cast<T> (или OfType<T>), чтобы получить правильный тип. Разница в том, что Cast<T> выдаст исключение, если обнаружит что-то, что не является T, тогда как OfType<T> просто игнорирует все, что не является T. Поскольку вы заявили, что ваша коллекция Только содержит LanguageEditorResource, разумно проверить это предположение с помощью Cast<T>, а не отбрасывать данные молча.

Также проверьте, что у вас есть «using System.Linq» (и вы ссылаетесь на System.Core (.NET 3.5; иначе LINQBridge с .NET 2.0), чтобы получить методы расширения Where.

На самом деле, стоило бы иметь в вашей коллекции реализацию IEnumerable<LanguageResource> - что вы могли бы довольно просто сделать, используя либо метод Cast<T>, либо блок итератора (yield return).

[редактировать] Основываясь на примечании Ричарда Пула - вы можете написать здесь свой общий контейнер своя, предположительно с T : LanguageResource (и используя этот T в Dictionary<string,T>, и реализуя IEnumerable<T> или ICollection<T>). Просто мысль.

В дополнение к ответу Марка Джи, и если вы можете это сделать, вы можете подумать об отказе от своего пользовательского класса LanguageResourceCollection в пользу общего List<LanguageResource>. Это решит вашу текущую проблему и избавится от этой неприятной пользовательской коллекции .NET 1.1.

Что ж, по-прежнему необходимо перейти от LanguageResource к LanguageEditorResource и отметить внутреннее использование Dictionary <,> - это не только, базовая оболочка коллекции.

Marc Gravell 06.11.2008 12:09

How can I dig into what LINQ generates to try and see what the problem is?

Linq здесь ничего не генерирует. Вы можете пройти через отладчик.

to try and improve my understanding of LINQ and learn how I can improve the design of my classes to work better with LINQ.

Методы System.Linq.Enumerable в значительной степени полагаются на контракт IEnumerable <T>. Вам необходимо понять, как ваш класс может создавать цели, поддерживающие этот контракт. Тип, который представляет T, важен!

Вы можете добавить этот метод в LanguageResourceCollection:

public IEnumerable<T> ParticularResources<T>()
{
  return _dict.Values.OfType<T>();
}

и назовите его:

_resources
  .ParticularResources<LanguageEditorResource>()
  .Where(r => r.IsDirty)

Этот пример имел бы больше смысла, если бы класс коллекции не реализовал IEnumerable <T> для того же самого _dict.Values. Дело в том, чтобы понять IEnumerable <T> и общую типизацию.

Другие вопросы по теме