一些背景信息;
Dictionary<string, LanguageResource> _dict
_dict.Values.GetEnumerator()
我有一个只包含LanguageEditorResource对象的LanguageResourceCollection _resources,并希望使用LINQ来枚举那些脏的,所以我尝试了以下内容。我的具体问题以粗体显示。
_resources.Where(r => (r as LanguageEditorResource).IsDirty)
两者都没有Intellisense显示的其他LINQ方法,但我仍然编码它,并告诉我“LanguageResourceCollection不包含'Where'的定义,也没有扩展方法......”。
为什么LanguageResourceCollection实现IEnumerable的方式阻止它支持LINQ?
如果我将查询更改为
(_resources as IEnumerable<LanguageEditorResource>).Where(r => r.IsDirty)
Intellisense显示LINQ方法并编译解决方案。但是在运行时我得到一个ArgumentNullException“Value不能为null。参数名称:source”。
这是我的LINQ代码中的问题吗?
这类课程的总体设计是否有问题?
我如何深入了解LINQ生成的内容以尝试查看问题所在?
我对这个问题的目标不是为特定问题找到解决方案,因为我现在必须使用其他(非LINQ)方法解决它,而是尝试提高我对LINQ的理解并学习如何改进我的类的设计,以便更好地使用LINQ。
答案 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>和通用打字。