与LINQ有些混淆

时间:2008-11-06 08:31:08

标签: c# .net linq linq-to-objects

一些背景信息;

  • LanguageResource是基类
  • LanguageTranslatorResource和LanguageEditorResource继承自LanguageResource
  • LanguageEditorResource定义IsDirty属性
  • LanguageResourceCollection是LanguageResource
  • 的集合
  • LanguageResourceCollection在Dictionary<string, LanguageResource> _dict
  • 内部保存LanguageResources
  • LanguageResourceCollection.GetEnumerator()返回_dict.Values.GetEnumerator()

我有一个只包含LanguageEditorResource对象的LanguageResourceCollection _resources,并希望使用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“Value不能为null。参数名称:source”。

    这是我的LINQ代码中的问题吗? 这类课程的总体设计是否有问题?
    我如何深入了解LINQ生成的内容以尝试查看问题所在?

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

3 个答案:

答案 0 :(得分: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)即可。

[编辑] 要在Richard Poole的注释基础上构建 - 您可以在此处编写自己的通用容器,大概使用T : LanguageResource(并在T中使用Dictionary<string,T>,并实施{ {1}}或IEnumerable<T>)。只是一个想法。

答案 1 :(得分:1)

除了Marc G的回答,如果您能够这样做,您可能需要考虑放弃自定义LanguageResourceCollection课程,转而使用通用List<LanguageResource>。这将解决您当前的问题并摆脱那令人讨厌的.NET 1.1ish自定义集合。

答案 2 :(得分:1)

  

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

Linq在这里没有产生任何东西。您可以使用调试器。

  

尝试提高我对LINQ的理解,并学习如何改进我的类的设计,以便更好地使用LINQ。

System.Linq.Enumerable方法严重依赖于IEnumerable&lt; T>合同。您需要了解您的课程如何生成支持此合同的目标。 T代表的类型很重要!

您可以将此方法添加到LanguageResourceCollection:

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

并通过以下方式调用:

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

如果集合类没有实现IEnumerable&lt;这个例子会更有意义。 T>反对同样的_dict.Values。重点是理解IEnumerable&lt; T>和通用打字。