在 ObservableCollection 上使用 Lambda 表达式
Posted
技术标签:
【中文标题】在 ObservableCollection 上使用 Lambda 表达式【英文标题】:Using Lambda Expression on an ObservableCollection 【发布时间】:2012-01-08 02:34:33 【问题描述】:在我的 Silverlight 4 应用程序中,我有一个 ObservableCollection,它由一个类的对象组成并由一个接口定义:
interface myInterface()
string Name get; set;
string Value get; set;
class myClass() : myInterface
...
ObservableCollection<myInterface> _collection;
在向集合添加新元素之前,我想确保名称属性不存在于当前集合元素中。 由于无法使用包含,我目前遍历所有元素并手动检查每个元素。
private bool CollectionContainsElement(string name2CheckAgainst)
foreach (myInterface item in _collection)
if (item.Name.Equals(name2CheckAgainst))
return true;
return false;
我读到这也可以通过 Lambda 表达式来实现,所以我写了以下内容:
if (!_collection.Contains(p => p.Name == name2CheckAgainst))
...
但是现在我收到一个错误,说“lambda 表达式无法转换为类型“myInterface”,因为它不是委托类型”。 (措辞可能不同,因为我是从德文翻译过来的)
我不确定我必须进行哪些更改才能使其正常工作。 using System.Linq;
包括在内。第二个问题(或者可能是主要问题):我已经读过,运行时从 Contains() 方法的 O(1) 更改为 O(n) - 这并不比我当前的检查快。那么将其更改为使用 lambda 是否有意义?最后,是否有另一种方法可以检查我的班级中现有的 Name-Property?
提前致谢, 弗兰克
【问题讨论】:
【参考方案1】:您不必编写 Contains 方法,Linq 的 Any 方法已经在这样做了:
if (!_collection.Any(p => p.Name == name2CheckAgainst))
如果要使用 Lambda,则必须更改 Contains 方法的原型以接受 Lambda(lambda 只是编写匿名函数的另一种方法):
private bool CollectionContainsElement(Func<myInterface, bool> lambda)
foreach (myInterface item in _collection)
if (lambda(item))
return true;
return false;
在这里使用 lambda 不会改变函数的复杂性,在这两种情况下都是 O(n)。所以这只是一个偏好问题。
【讨论】:
非常感谢,看来我误读了包含方法中 lamda 的示例。使用 Any 很明显 :)【参考方案2】:Contains 不是 LINQ 扩展,因此您不能对它使用 lambda 表达式。它旨在检查提供的 object 是否存在于列表中。
正如其他人所说,Any 是等效的 lambda 表达式兼容扩展方法
【讨论】:
【参考方案3】:您可以使用Linq Any() method。可以这样使用:
if (!_collection.Any(p => p.Name == name2CheckAgainst))
contains 方法为 O(1) 的原因在于,它在幕后将您的集合加载到 HashTable(或类似的)中,并使用哈希码(随后调用 Equals)来检查元素是否存在.
【讨论】:
以上是关于在 ObservableCollection 上使用 Lambda 表达式的主要内容,如果未能解决你的问题,请参考以下文章
WPF ObservableCollection 异步调用问题