Anonymous Delegates and generic Lists in C#
Asked Answered
P

5

5

Can you explain me code below :

private static List<Post> _Posts;
public static Post GetPost(Guid id)
{
    return _Posts.Find(delegate(Post p)
    {
        return p.Id == id;
    });
}
  1. What is the point to find an object in a generic list by that way ? He can simply iterate the list.

  2. How this delegated method called for each element of list ?

NOTE : if this has a common name, can you update my question's title ?

Thanks !

Pectoral answered 4/2, 2009 at 21:18 Comment(0)
M
19

You're quite right he can iterate over the list, you can think of the code in your question as being conceptually the same as the following:

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

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

    return p;
}

It requires less code to write your snippet and importantly you are now saying what you want to be found and not exactly how to find it:

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

In C# 3.0 this can be shortened further using what is called a "lambda expression" to:

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

Using the least amount of readable code to achieve the same goal makes both writers and readers of that code happier.

Makkah answered 4/2, 2009 at 21:18 Comment(2)
great answer, since this guys big on naming things you might want to point out that that 3rd example is called a lambda expressionQuorum
@sixlettervariables: agreed, readable code certainly makes me happier :-)Makkah
S
7

He is using an anonymous delegate. He could have used a lambda expression instead:

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

Also, wrapping access to the list in a method achieves nothing in this case and exposes the elements of the list to external callers. This is bad practice.

Salangi answered 4/2, 2009 at 21:22 Comment(7)
Actually, find isn't a Linq extension method. It's part of the List class itself and has been around since .NET 2.0Metaplasia
Your 'bad practice' link is broken.Dagnah
@siz: Any method that takes any kind of delegate (Predicate, Func, or your own kind) can be called using anonymous functions / lambda expressions. They get compiled down to actual methods in the IL, and then a reference is passed to them when the method is called.Metaplasia
+1 BFree You can also tell this isn't an extension method because extensions can't have the same name as an existing method.Councilor
@Adam: You can have an extension method the same name and signature as a native method. It's just useless for that class. @flesh: There is not enough code to say that this style rule is being violated.Vladikavkaz
thedric, that was the wrong link. the code above is bad because it has a private static list with its members being returned to clients publicly, who can then change their state.Salangi
ah, missed the change. waves fist Accursed Async Web!Vladikavkaz
N
3
  1. List basically goes through each element and checks whether the element returns true for that Predicate<T>. It is essentially a shortcut so that you don't have to iterate over the list. List<T>.Find(Predicate<T>) might also have some built-in optimizations.
  2. You call a delegate using the syntax:

delegateInstance(arg1,arg2);

Natal answered 4/2, 2009 at 21:24 Comment(0)
S
1

If you are using C# 3.0 or later you can use Linq to find objects quickly in a List.

public static Post GetPost(Guid id)
{
    return (from p in _Posts
            where p.Id == id
            select p).First();
}
Sentimental answered 4/2, 2009 at 21:23 Comment(0)
V
1

List.Find(Predicate match) is NOT a LINQ extension method, because this method has been in the framework since 2.0, as is indicated by MSDN. Second, there is nothing wrong with using Find(). It tends to be more readable than its alternatives:

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();
}

Using List.Find() tells you immediately that you are look for an item, while the other you have to follow logic to ascertain this. Find() basically encapsulates the iteration over the list items. If you had a method on the Post class like public bool HasId(Guid id) then you could write

_Post.Find(post.HasId(id));
Vladikavkaz answered 4/2, 2009 at 22:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.