tags:

views:

713

answers:

3

I am creating a Distinct extension method where I can pass in the criteria like the following.

persons.Distinct(p => p.Name);

I got the code from the web but I am having a hard time understanding the purpose of Func. Also, when I say p=> p.Name Am I sending the String Name or Am I sending the complete Person object. Here is the new Distinct method:

 public static class ExtensionMethods
    {
        public static IEnumerable<T> Distinct<T>(
            this IEnumerable<T> list, Func<T,object> checker)
        {
            return list.Distinct(new GenericComparer<T>(checker)); 
        }
    }

    public class GenericComparer<T> : IEqualityComparer<T>
    {
        private Func<T, object> _checker; 

        public GenericComparer(Func<T,object> checker)
        {
            _checker = checker; 
        }

        public bool Equals(T x, T y)
        {
            return _checker(x).Equals(_checker(y));
        }

        public int GetHashCode(T obj)
        {
            return _checker(obj).GetHashCode(); 
        }
    }

And here is the usage:

static void Main(string[] args)
        {
            var persons = new List<Person>()
                              {
                                  new Person() { Id = 1, Name = "Mary"}, 
                                  new Person() {Id = 2, Name="John"}, 
                                  new Person() { Id = 3, Name = "Mary"}
                              };


            var uniquePersons = persons.Distinct(p => p.Name); 

            foreach(var person in uniquePersons)
            {
                Console.WriteLine(person.Name);
            }

        }
+22  A: 

When you do this:

persons.Distinct(p => p.Name);

You're basically creating a function on the fly (using lambda expressions), that looks like this:

string theFunction(Person p)
{
    return p.Name;
}

This is a function that fits the signature of a Func<Person,String> delegate. The Distinct method can take a delegate (basically a function pointer) which it uses to determine whether or not an element is distinct - in your case, only unique strings (returned by the function above) will be considered "distinct" elements. This delegate is run on each element of your "persons" enumerable, and the results of those functions are used. It then creates a sequence (IEnumerable<Person>) from those elements.

Reed Copsey
+1, but "In your case, an element is distinct if no other element has the same `Name`. If more than one item in the source has the same name, only the first of them will be present in the result." Also, no overload of the `Distict()` method takes a selector - did you write your own?
280Z28
the OP question shows how the Distinct extension is defined...
ShuggyCoUk
Yes, I got a Distinct extension method of the internet! I did not write it myself!
+4  A: 
Func<T, TResult>

defines a function that accepts one parameter (of type T) and returns an object (of type TResult).

In your case, if you want a function that takes a Person object and returns a string...you'd want

Func<Person, string>

which is the equivalent of:

string Function(Person p)
{
    return p.Name;
}
Justin Niessner
A: 

You are getting back the distinct People, under the assumption that two People are the same if they have the same name

If you want a distinct set of names, you can use this:

IEnumerable<String> names = persons.Select(p => p.Name).Distinct();
Neil