2008-11-06 4 views
0

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

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

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

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

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

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

  2. Если изменить запрос к

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

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

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

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

ответ

6

Это звучит, как ваша коллекция реализует 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>, вместо того, чтобы молча отбрасывать данные.

Проверьте также, что у вас есть "с помощью 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>). Просто мысль.

1

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

+0

Ну, ему все равно нужно получить от LanguageResource до LanguageEditorResource и обратить внимание на внутреннее использование словаря <,> - это не * просто * базовая обертка коллекции. – 2008-11-06 09:09:01

1

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

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

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

System.Linq.Enumerable методы в значительной степени зависят от IEnumerable < 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> и типичную типизацию.

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