0

一些背景资料;

  • 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)

    Intellisense 没有显示其他 LINQ 方法,但我还是对其进行了编码,并被告知“LanguageResourceCollection 不包含'Where'的定义并且没有扩展方法......”。

    为什么 LanguageResourceCollection 实现 IEnumerable 的方式使其无法支持 LINQ?

  2. 如果我将查询更改为

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

    Intellisense,则会显示 LINQ 方法并且解决方案会编译。但是在运行时我得到一个 ArgumentNullException “值不能为空。参数名称:源”。

    这是我的 LINQ 代码中的问题吗?
    类的一般设计有问题吗?
    如何深入研究 LINQ 生成的内容以尝试查看问题所在?

我对这个问题的目标不是为特定问题找到解决方案,因为我现在必须使用其他(非 LINQ)方法来解决它,而是尝试提高我对 LINQ 的理解并学习如何改进设计我的课程可以更好地使用 LINQ。

4

3 回答 3

6

这听起来像您的收藏工具IEnumerable,而不是IEnumerable<T>,因此您需要:

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

请注意,它Enumerable.Where是在 上定义的IEnumerable<T>,而不是IEnumerable- 如果您有非泛型类型,则需要使用Cast<T>(或OfType<T>) 来获得正确的类型。不同之处在于,Cast<T>如果它发现不是 a 的东西,就会抛出异常T,而 where-asOfType<T>会简单地忽略任何不是 a 的东西T。由于您已声明您的集合包含,因此使用而不是静默删除数据LanguageEditorResource来检查该假设是合理的。Cast<T>

还要检查您是否有“使用 System.Linq”(并且正在引用 System.Core(.NET 3.5;否则 LINQBridge 与 .NET 2.0)以获取Where扩展方法。

实际上,实现你的集合是值得的IEnumerable<LanguageResource>——你可以很简单地使用Cast<T>方法或迭代器块 ( yield return)。

[编辑] 以 Richard Poole 的注释为基础 - 您可以在这里编写自己的通用容器,大概使用T : LanguageResource(并TDictionary<string,T>, 和实现IEnumerable<T>or中使用它ICollection<T>)。只是一个想法。

于 2008-11-06T08:40:46.457 回答
1

除了 Marc G 的回答之外,如果您能够这样做,您可能需要考虑放弃您的自定义LanguageResourceCollection类以支持泛型List<LanguageResource>. 这将解决您当前的问题并摆脱讨厌的 .NET 1.1ish 自定义集合。

于 2008-11-06T09:02:26.600 回答
1

如何深入研究 LINQ 生成的内容以尝试查看问题所在?

Linq 在这里没有生成任何东西。您可以使用调试器单步执行。

尝试提高我对 LINQ 的理解,并了解如何改进我的课程设计以更好地使用 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)

如果集合类没有针对相同的 _dict.Values 实现 IEnumerable< T >,则此示例将更有意义。重点是理解 IEnumerable<T> 和泛型类型。

于 2008-11-06T16:25:30.170 回答