2010-09-03 27 views
35

Tôi có một danh sách các đối tượng tùy chỉnh được nhập mạnh mẽ, MyObject, có một Id thuộc tính cùng với một số thuộc tính khác.
Giả sử Id của MyObject xác định nó là duy nhất và tôi muốn kiểm tra xem bộ sưu tập của tôi chưa có đối tượng MyObject có Id là 1 trước khi tôi thêm MyObject mới vào bộ sưu tập.
Tôi muốn sử dụng nếu (! List.Contains (myObj)) nhưng làm cách nào để thực thi thực tế là chỉ một hoặc hai thuộc tính của MyObject xác định nó là duy nhất?
Tôi có thể sử dụng IComparable? Hay tôi chỉ phải ghi đè lên phương thức Equals nhưng tôi cần kế thừa thứ gì đó đầu tiên là đúng không?Collection.Contains() sử dụng để kiểm tra các đối tượng hiện có là gì?



Cảm ơn

Trả lời

36

List<T>.Contains sử dụng EqualityComparer<T>.Default, mà lần lượt sử dụng IEquatable<T> nếu loại thực hiện nó, hoặc object.Equals khác.

Bạn chỉ có thể thực hiện IEquatable<T> nhưng đó là một ý tưởng tốt để ghi đè object.Equals nếu bạn làm như vậy, và rất ý tưởng tốt để ghi đè GetHashCode() nếu bạn làm điều đó:

public class SomeIDdClass : IEquatable<SomeIDdClass> 
{ 
    private readonly int _id; 
    public SomeIDdClass(int id) 
    { 
     _id = id; 
    } 
    public int Id 
    { 
     get { return _id; } 
    } 
    public bool Equals(SomeIDdClass other) 
    { 
     return null != other && _id == other._id; 
    } 
    public override bool Equals(object obj) 
    { 
     return Equals(obj as SomeIDdClass); 
    } 
    public override int GetHashCode() 
    { 
     return _id; 
    } 
} 

Lưu ý rằng mã băm liên quan theo tiêu chí bình đẳng. Điều này là quan trọng.

Điều này cũng làm cho nó áp dụng cho bất kỳ trường hợp nào khác mà bình đẳng, như được xác định bằng cách có cùng một ID, là hữu ích.Nếu bạn có yêu cầu một lần để kiểm tra xem danh sách có đối tượng như vậy không, thì tôi có thể đề xuất chỉ cần thực hiện:

return someList.Any(item => item.Id == cmpItem.Id); 
4

Bạn có thể sử dụng LINQ để làm điều này khá dễ dàng.

var result = MyCollection.Any(p=>p.myId == Id); 
if(result) 
{ 
    //something 
} 
+0

ồ phải. điều đó có vẻ ổn. – topwik

+5

Hơi ngắn gọn hơn sẽ là: MyCollection.Any (x => x.myId == Id) –

+8

Không chỉ ngắn gọn hơn, nhưng điều này sẽ phải lặp qua toàn bộ bộ sưu tập. 'Bất kỳ' sẽ ngắn ngủi trong trận đấu đầu tiên. –

0

Bạn có thể sử dụng IEquatable<T>. Thực hiện điều này trong lớp của bạn, và sau đó kiểm tra xem T có được chuyển tới Equals có cùng Id như this.Id. Tôi chắc chắn rằng nó hoạt động để kiểm tra một từ khóa trong một từ điển, nhưng tôi đã không sử dụng nó cho một bộ sưu tập.

2

Bạn có thể ghi đè lên Equals và GetHashCode, thực hiện một IEqualityComparer<MyObject> và sử dụng rằng trong Contains cuộc gọi, hoặc sử dụng một phương pháp khuyến nông như Any

if (!myList.Any(obj => obj.Property == obj2.Property && obj.Property2 == obj2.Property2)) 
    myList.Add(obj2); 
+0

+1, đây là một giải pháp hiệu suất cao tốt, đặc biệt nếu bạn sử dụng bộ hoặc từ điển. (nói đến điểm Bằng/GetHashCode) –

27

List<T> sử dụng comparer trả về bởi EqualityComparer<T>.Default và theo documentation cho rằng :

Thuộc tính mặc định sẽ kiểm tra xem loại T có thực hiện System.IEquatable (Giao diện T) và, nếu có, trả về EqualityComparer (Của T) sử dụng triển khai đó. Nếu không, nó sẽ trả về một EqualityComparer (Of T) có sử dụng các ghi đè của Object.equals và Object.GetHashCode cung cấp bởi T.

Vì vậy, bạn có thể thực hiện IEquatable<T> trên lớp tùy chỉnh của bạn, hoặc ghi đè lên Các phương pháp Equals (và GetHashCode) để so sánh các thuộc tính bạn yêu cầu. Hoặc bạn có thể sử dụng LINQ:

bool contains = list.Any(i => i.Id == obj.Id); 
+0

Tôi sẽ đi với câu lệnh Linq. Nếu bạn muốn, bạn có thể thực hiện một phương pháp mở rộng Chứa (danh sách này danh sách, T mục, Func so sánh) mà sẽ trông giống như List.Contains nhưng thêm khả năng cung cấp một đại biểu so sánh. Nó sẽ quấn một câu lệnh Linq tương tự như những gì được cung cấp ở đây. – KeithS

+0

+1 cho LINQ - Tôi đang tìm đoạn mã chính xác này – elwyn

+0

+1 cho LINQ, vì nó cho phép bạn so sánh các lớp từ các nguồn bên ngoài. Và cho mã sang trọng – PPC

0

Lớp trợ giúp xác định đầu tiên với IEqualityComparer.

public class MyEqualityComparer<T> : IEqualityComparer<T> 
{ 
    Func<T, int> _hashDelegate; 

    public MyEqualityComparer(Func<T, int> hashDelegate) 
    { 
     _hashDelegate = hashDelegate; 
    } 

    public bool Equals(T x, T y) 
    { 
     return _hashDelegate(x) == _hashDelegate(y); 
    } 

    public int GetHashCode(T obj) 
    { 
     return _hashDelegate(obj); 
    } 
} 

Sau đó, trong mã của bạn, chỉ cần xác định so sánh và sử dụng nó:

var myComparer = new MyEqualityComparer<MyObject>(delegate(MyObject obj){ 
    return obj.ID; 
}); 

var result = collection 
    .Where(f => anotherCollection.Contains(f.First, myComparer)) 
    .ToArray(); 

Bằng cách này bạn có thể xác định cách cách bình đẳng được tính mà không sửa đổi các lớp học của bạn. Bạn cũng có thể sử dụng nó để xử lý đối tượng từ thư viện của bên thứ ba vì bạn không thể sửa đổi mã của họ.

Các vấn đề liên quan