C#中的匿名委托和通用列表

5
你能为我解释一下下面的代码吗:

以下是代码:

private static List<Post> _Posts;
public static Post GetPost(Guid id)
{
    return _Posts.Find(delegate(Post p)
    {
        return p.Id == id;
    });
}
  1. 通过这种方式在一个通用列表中查找对象的意义是什么?他可以简单地遍历列表。

  2. 这个委托方法是如何为列表中的每个元素调用的?

注意:如果这有一个常见的名称,你能更新我的问题标题吗?

谢谢!

5个回答

19

你说得很对,他可以迭代列表,你可以将你问题中的代码概念化为以下代码:

private static Post GetPost(Guid id)
{
    Post p = default(Post);

    foreach (Post post in _Posts)
    {
        if (post.Id == id)
        {
            p = post;
            break;
        }
    }

    return p;
}

使用这种方法,您需要编写的代码较少,更重要的是,现在您可以说出您要找到什么,而不是如何找到它:

private static Post GetPost(Guid id)
{
    return _Posts.Find(delegate(Post p)
    {
        return p.Id == id;
    });
}

在C# 3.0中,可以使用所谓的“lambda表达式”进一步简化为:

private static Post NewGetPost(Guid id)
{
    return _Posts.Find(p => p.Id == id);
}

使用最少量的易读代码来实现相同的目标可以让编写者和读者都更加愉快。


很好的回答,由于这个人非常注重命名,你可能想指出第三个例子被称为lambda表达式。 - bendewey
@sixlettervariables:同意,易读的代码确实让我更开心 :-) - Peter McG

7
他正在使用匿名委托。他本可以使用lambda表达式替代:
Posts.Find(p => p.Id == id)

此外,在这种情况下,将列表访问封装在方法中并没有任何作用,并且将列表的元素暴露给外部调用者。这是不好的做法。

实际上,Find不是Linq扩展方法。它是List类本身的一部分,并且自.NET 2.0以来就存在。 - BFree
你的“不良实践”链接已经失效。 - Erik Forbes
@siz:任何接受委托(Predicate、Func或自定义类型)的方法都可以使用匿名函数/lambda表达式进行调用。它们会被编译成实际的IL方法,然后在调用方法时将引用传递给它们。 - BFree
+1 BFree。您也可以看出这不是扩展方法,因为扩展方法不能与现有方法同名。 - Adam Lassek
@Adam: 你可以创建一个与本地方法同名同参数签名的扩展方法,但这对该类没有用处。 @flesh: 没有足够的代码来确定是否违反了此样式规则。 - Thedric Walker
显示剩余2条评论

3
  1. List<T>.Find(Predicate<T>)基本上遍历每个元素,并检查该元素是否对Predicate<T>返回true。它本质上是一种快捷方式,使您无需遍历列表。List<T>.Find(Predicate<T>)可能还具有一些内置优化。
  2. 您可以使用以下语法调用委托:

delegateInstance(arg1,arg2);


1

如果您使用的是C# 3.0或更高版本,您可以使用Linq在List中快速查找对象。

public static Post GetPost(Guid id)
{
    return (from p in _Posts
            where p.Id == id
            select p).First();
}

1

List.Find(Predicate match)并不是一个LINQ扩展方法,因为根据MSDN所示,这个方法从2.0版本开始就一直存在于框架中。

其次,使用Find()没有任何问题。它往往比其他替代方法更易读:

经典方法:

public static Post GetPost(Guid id)
{
  bool found = false;

  foreach(post in _Posts)
  { 
    if post.Id == id return post;
  }
  return default(Post);
}

LINQ:
public static Post GetPost(Guid id)
{
  var post = (
    from p in _Posts 
    where p.Id = id 
    select p
  ).FirstOrDefault();
}

使用List.Find()可以立即告诉您正在查找一个项目,而其他方法需要遵循逻辑来确定这一点。Find()基本上封装了对列表项的迭代。如果您在Post类上有一个像public bool HasId(Guid id)这样的方法,那么您可以编写

_Post.Find(post.HasId(id));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接