Анонимные делегаты и общие списки в C # - PullRequest
5 голосов
/ 05 февраля 2009

Можете ли вы объяснить мне код ниже:

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 голосов
/ 05 февраля 2009

Вы совершенно правы, он может перебирать список, вы можете думать, что код в вашем вопросе концептуально совпадает со следующим:

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 это можно еще больше сократить, используя так называемое « лямбда-выражение » до:

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

Использование наименьшего количества читаемого кода для достижения одной и той же цели делает авторов и читателей этого кода счастливее.

7 голосов
/ 05 февраля 2009

Он использует анонимного делегата. Вместо этого он мог бы использовать лямбда-выражение :

Posts.Find(p => p.Id == id)

Кроме того, перенос доступа к списку в методе в этом случае ничего не дает и предоставляет элементы списка внешним вызывающим объектам. Это плохая практика.

3 голосов
/ 05 февраля 2009
  1. Список в основном проходит через каждый элемент и проверяет, возвращает ли элемент значение true для этого Predicate<T>. Это по сути ярлык, так что вам не нужно перебирать список. List<T>.Find(Predicate<T>) может также иметь некоторые встроенные оптимизации.
  2. Вы вызываете делегата, используя синтаксис:

delegateInstance(arg1,arg2);

1 голос
/ 05 февраля 2009

List.Find (Predicate match) НЕ является методом расширения LINQ, поскольку этот метод используется в платформе с 2.0, как указано в MSDN. Во-вторых, нет ничего плохого в использовании Find (). Он имеет тенденцию быть более читабельным, чем его альтернативы:

Classic:

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));
1 голос
/ 05 февраля 2009

Если вы используете C # 3.0 или более позднюю версию, вы можете использовать Linq для быстрого поиска объектов в списке.

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