views:

1604

answers:

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 !

+6  A: 

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.

flesh
very helpful, thank you !
Canavar
Actually, find isn't a Linq extension method. It's part of the List class itself and has been around since .NET 2.0
BFree
bfree, you're right, thanks
flesh
Your 'bad practice' link is broken.
Erik Forbes
@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.
BFree
+1 BFree You can also tell this isn't an extension method because extensions can't have the same name as an existing method.
Adam Lassek
@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.
Thedric Walker
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.
flesh
ah, missed the change. *waves fist* Accursed Async Web!
Thedric Walker
+1  A: 

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();
}
thaBadDawg
+3  A: 
  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);

siz
+16  A: 

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.

Peter McGrattan
great answer, since this guys big on naming things you might want to point out that that 3rd example is called a lambda expression
bendewey
@bendewey: no problem, see edit
Peter McGrattan
Using the least amount of 'readable' code to achieve the same goal...
sixlettervariables
@sixlettervariables: agreed, readable code certainly makes me happier :-)
Peter McGrattan
+1  A: 

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));
Thedric Walker