2009-07-31 39 views
19

Tôi đang tạo một phương pháp mở rộng Riêng biệt, nơi tôi có thể vượt qua các tiêu chí như sau.Func <T,TResult> hoạt động như thế nào?

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

Tôi nhận được mã từ web nhưng tôi gặp khó khăn khi hiểu mục đích của Func<T, TResult>. Ngoài ra, khi tôi nói p => p.Name tôi có gửi StringName hoặc tôi đang gửi đối tượng hoàn chỉnh Person? Dưới đây là phương pháp riêng biệt mới:

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

Và đây là cách sử dụng:

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

Trả lời

34

Khi bạn làm điều này:

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

Bạn đang cơ bản tạo ra một chức năng một cách nhanh chóng (using lambda expressions), trông giống như sau:

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

Đây là một chức năng phù hợp với chữ ký của một đại biểu Func<Person,String>. Phương thức Distinct có thể lấy một delegate (về cơ bản là một con trỏ hàm) mà nó dùng để xác định một phần tử có phân biệt hay không - trong trường hợp của bạn, chỉ các chuỗi duy nhất (được trả về bởi hàm trên) sẽ được coi là các phần tử "khác biệt". Đại biểu này được chạy trên mỗi phần tử của "người" của bạn liệt kê, và kết quả của các chức năng đó được sử dụng. Sau đó nó tạo ra một chuỗi (IEnumerable<Person>) từ các phần tử đó.

+0

+1, nhưng "Trong trường hợp của bạn, phần tử là khác biệt nếu không có phần tử nào khác có cùng tên'. Nếu nhiều hơn một mục trong nguồn có cùng tên, chỉ có một mục đầu tiên trong số đó sẽ có mặt trong kết quả. "Ngoài ra, không có quá tải của phương thức' Distict() 'có bộ chọn - bạn có viết riêng của mình không? –

+0

Câu hỏi OP cho thấy cách mở rộng khác biệt được xác định ... – ShuggyCoUk

+0

Có, tôi có một phương pháp mở rộng khác biệt của internet! Tôi không viết nó bản thân mình –

8
Func<T, TResult> 

xác định hàm nhận một tham số (loại T) và trả về đối tượng (kiểu TResult).

Trong trường hợp của bạn, nếu bạn muốn có một chức năng mà phải mất một đối tượng Person và trả về một chuỗi ... bạn muốn

Func<Person, string> 

đó là tương đương với:

string Function(Person p) 
{ 
    return p.Name; 
} 
0

Bạn đang lấy lại những người khác biệt, theo giả định rằng hai người giống nhau nếu họ có cùng tên

Nếu bạn muốn có một bộ tên riêng biệt, bạn có thể sử dụng điều này:

IEnumerable<String> names = persons.Select(p => p.Name).Distinct(); 
Các vấn đề liên quan