2009-02-04 3 views
4

Можете ли вы объяснить мне код ниже:анонимных делегатов и общие списки в C#

private static List<Post> _Posts; 
public static Post GetPost(Guid id) 
{ 
    return _Posts.Find(delegate(Post p) 
    { 
     return p.Id == id; 
    }); 
} 
  1. Какой смысл найти объект в общем списке по этому пути? Он может просто перебирать список.

  2. Как этот делегированный метод вызывается для каждого элемента списка?

Примечание:, если это имеет общее название, вы можете обновить название моего вопроса в?

Спасибо!

ответ

18

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

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 expression», чтобы:

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

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

+0

Отличный ответ, так как эти ребята сильно поименовали вещи, вы можете указать, что этот третий пример называется выражением лямбда – bendewey

+0

@bendewey: нет проблем, см. Edit –

+0

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

6

Он пользуется анонимным делегатом. Он мог бы использовать вместо lambda expression:

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

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

+0

очень полезно, спасибо! – Canavar

+0

Фактически, поиск не является методом расширения Linq. Это часть самого класса List и существует с .NET 2.0 – BFree

+0

bfree, вы правы, спасибо – flesh

1

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

public static Post GetPost(Guid id) 
{ 
    return (from p in _Posts 
      where p.Id == id 
      select p).First(); 
} 
3
  1. Список в основном проходит через каждый элемент и проверяет, возвращает ли элемент верно для этого Predicate<T>. Это, по сути, ярлык, поэтому вам не нужно перебирать список. List<T>.Find(Predicate<T>) может также иметь встроенные оптимизации.
  2. Вы называете делегата, используя следующий синтаксис:

delegateInstance(arg1,arg2);

1

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)); 
Смежные вопросы