Tôi đang tìm thực tiễn tốt nhất thế giới thực, cách người khác có thể đã triển khai các giải pháp với các tên miền phức tạp.Thực tiễn tốt nhất được đề nghị để sử dụng IEqualityComparer <T> là gì?
Trả lời
Đây là những gì MSDN đã nói về IEqualityComparer (không chung chung):
Giao diện này cho phép thực hiện các tùy chỉnh so sánh bình đẳng cho các bộ sưu tập. Tức là, bạn có thể tạo định nghĩa bình đẳng của riêng mình và xác định rằng định nghĩa này được sử dụng với một loại bộ sưu tập chấp nhận giao diện
IEqualityComparer
. Trong Khuôn khổ .NET, các hàm tạo của các loại bộ sưu tậpHashtable
,NameValueCollection
vàOrderedDictionary
chấp nhận giao diện này.Giao diện này chỉ hỗ trợ so sánh bình đẳng. Tùy chỉnh các so sánh để sắp xếp và sắp xếp được cung cấp bởi giao diện
IComparer
.
Có vẻ như phiên bản chung của giao diện này thực hiện cùng một chức năng nhưng được sử dụng cho các bộ sưu tập Dictionary<(Of <(TKey, TValue>)>)
.
Theo như thực tiễn tốt nhất xung quanh việc sử dụng giao diện này cho mục đích của riêng bạn. Tôi sẽ nói rằng thực hành tốt nhất là sử dụng nó khi bạn đang phát triển hoặc thực hiện một lớp có chức năng tương tự như các bộ sưu tập .NET framework đã đề cập ở trên và nơi bạn muốn thêm khả năng tương tự vào bộ sưu tập của riêng mình. Điều này sẽ đảm bảo rằng bạn nhất quán với cách .NET framework sử dụng giao diện.
Nói cách khác hỗ trợ việc sử dụng giao diện này nếu bạn đang phát triển bộ sưu tập tùy chỉnh và bạn muốn cho phép người tiêu dùng kiểm soát sự bình đẳng được sử dụng trong một số LINQ và các phương pháp liên quan đến bộ sưu tập (ví dụ: Sắp xếp).
Tôi sẽ nói rằng việc sử dụng tốt nhất sẽ là khi bạn cần phải cắm các quy tắc bình đẳng khác nhau cho một thuật toán nhất định. Cũng giống như cách mà thuật toán sắp xếp có thể chấp nhận một số IComparer<T>
, thuật toán tìm kiếm có thể chấp nhận một số IEqualityComparer<T>
Danh sách này sử dụng giao diện này rất nhiều, vì vậy bạn có thể nói a.Substract (b) hoặc các hàm đẹp khác.
Chỉ cần nhớ: Nếu bạn là đối tượng không trả về cùng một Hashcode, thì Equals không được gọi.
Tôi đã làm như sau, tôi không chắc đó có phải là thực tiễn tốt nhất trong thế giới thực hay không, nhưng nó hoạt động tốt cho tôi. :)
public class GenericEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, Boolean> _comparer;
private Func<T, int> _hashCodeEvaluator;
public GenericEqualityComparer(Func<T, T, Boolean> comparer)
{
_comparer = comparer;
}
public GenericEqualityComparer(Func<T, T, Boolean> comparer, Func<T, int> hashCodeEvaluator)
{
_comparer = comparer;
_hashCodeEvaluator = hashCodeEvaluator;
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
return _comparer(x, y);
}
public int GetHashCode(T obj)
{
if(obj == null) {
throw new ArgumentNullException("obj");
}
if(_hashCodeEvaluator == null) {
return 0;
}
return _hashCodeEvaluator(obj);
}
#endregion
}
Sau đó, bạn có thể sử dụng nó trong bộ sưu tập của mình.
var comparer = new GenericEqualityComparer<ShopByProduct>((x, y) => x.ProductId == y.ProductId);
var current = SelectAll().Where(p => p.ShopByGroup == group).ToList();
var toDelete = current.Except(products, comparer);
var toAdd = products.Except(current, comparer);
Nếu bạn cần hỗ trợ tùy chỉnh GetHashCode() chức năng, sử dụng các nhà xây dựng thay thế để cung cấp một lambda để làm việc tính toán thay thế:
var comparer = new GenericEqualityComparer<ShopByProduct>(
(x, y) => { return x.ProductId == y.ProductId; },
(x) => { return x.Product.GetHashCode()}
);
Tôi hy vọng điều này sẽ giúp. =)
Bất kỳ lúc nào bạn cân nhắc sử dụng IEqualityComparer<T>
, hãy tạm dừng để suy nghĩ xem liệu lớp học có thể được thực hiện để thực hiện IEquatable<T>
thay thế hay không. Nếu một mã số Product
luôn luôn được so sánh bằng ID, chỉ cần xác định nó để được so sánh như vậy để bạn có thể sử dụng trình so sánh mặc định.
Điều đó nói rằng, vẫn còn một vài trong số lý do khiến bạn muốn có một comparer tùy chỉnh:
- Nếu có nhiều cách thể hiện của một lớp có thể được coi là bình đẳng. Ví dụ tốt nhất về điều này là một chuỗi, trong đó khung cung cấp sáu bộ so sánh khác nhau trong
StringComparer
. - Nếu lớp học được xác định theo cách mà bạn không thể xác định nó là
IEquatable<T>
. Điều này sẽ bao gồm các lớp được định nghĩa bởi những người khác và các lớp được tạo ra bởi trình biên dịch (đặc biệt là các kiểu ẩn danh, sử dụng một so sánh thuộc tính khôn ngoan theo mặc định).
Nếu bạn quyết định cần so sánh, bạn chắc chắn có thể sử dụng trình so sánh tổng quát (xem câu trả lời của DMenT), nhưng nếu bạn cần sử dụng lại logic đó, bạn nên đóng gói nó trong một lớp chuyên dụng. Bạn thậm chí có thể khai báo nó bằng cách kế thừa từ cơ sở chung:
class ProductByIdComparer : GenericEqualityComparer<ShopByProduct>
{
public ProductByIdComparer()
: base((x, y) => x.ProductId == y.ProductId, z => z.ProductId)
{ }
}
Khi sử dụng, bạn nên tận dụng lợi thế của các bộ so sánh khi có thể. Ví dụ: thay vì gọi ToLower()
trên mỗi chuỗi được sử dụng làm khóa từ điển (logic sẽ được rải rác trên ứng dụng của bạn), bạn nên khai báo từ điển để sử dụng phân biệt chữ hoa chữ thường StringComparer
. Cũng vậy với các toán tử LINQ chấp nhận một trình so sánh. Nhưng một lần nữa, luôn luôn xem xét nếu các hành vi tương đương mà nên được nội tại cho lớp chứ không phải được định nghĩa bên ngoài.
Xem bài đăng này giải pháp thay thế (tốt hơn): Wrap a delegate in an IEqualityComparer
Cuộn xuống phần trên KeyEqualityComparer và đặc biệt là phần trên the importance of GetHashCode. Có toàn bộ discussion về lý do tại sao obj.GetHashCode();
(như được đề xuất bởi bài của DMenT) là sai và chỉ nên trả về 0 để thay thế.
- 1. Thực tiễn tốt nhất để sử dụng lưu trữ cục bộ luồng trong .NET là gì?
- 2. Thực tiễn tốt nhất về CDN là gì?
- 3. Thực tiễn tốt nhất để sử dụng nhiều tệp .gitignore
- 4. Thực tiễn tốt nhất để sử dụng partials trong Rails
- 5. DTO: thực tiễn tốt nhất
- 6. Bộ sưu tập của Coldfusion CFC Thực tiễn tốt nhất/được khuyến nghị?
- 7. JavaScript Thực tiễn tốt nhất
- 8. Thực tiễn tốt nhất khi sử dụng ổ cắm web?
- 9. nhibernate: thực tiễn tốt nhất để thực hiện bình đẳng là gì?
- 10. Thực tiễn tốt nhất để tạo các đối tượng được sử dụng trong/vòng lặp foreach
- 11. Thực tiễn tốt nhất để phát hiện tỷ lệ pixel/mật độ là gì?
- 12. Thực tiễn tốt nhất để hiển thị thông báo lỗi
- 13. thực tiễn tốt nhất để kết hợp các kết nối Hive JDBC là gì
- 14. Android strings.xml Thực tiễn tốt nhất?
- 15. Thực tiễn tốt nhất để đặt thuộc tính html qua PHP là gì?
- 16. Thực tiễn tốt nhất để xử lý các ngoại lệ khi sử dụng lệnh ràng buộc trong WPF là gì?
- 17. UIView Vẽ thực tiễn tốt nhất
- 18. Thực tiễn tốt nhất để liên lạc giữa các cá thể EC2 của Amazon là gì?
- 19. Giao dịch NHibernate Thực tiễn tốt nhất
- 20. Thực tiễn tốt nhất để đối phó với vấn đề kết thúc giao diện điều khiển là gì?
- 21. Thực tiễn tốt nhất để thiết lập liên kết với factory_girl trong dưa chuột là gì?
- 22. CXF Wsdl2Java Thực tiễn tốt nhất
- 23. Thực tiễn tốt nhất của Lucene.Net
- 24. iOS Facebook SDK - Thực tiễn tốt nhất?
- 25. C#: Thực tiễn tốt nhất Debug.Print
- 26. NSDateFormatter được chia sẻ - Thực tiễn tốt nhất?
- 27. CSS @import Thực tiễn tốt nhất
- 28. Thực tiễn tốt nhất cho quản lý id sự kiện là gì?
- 29. Thực tiễn tốt nhất cho kích thước trường dữ liệu chuỗi là gì?
- 30. Thực tiễn tốt nhất về Sitecore
Sự cố: không thể giả định rằng 'obj.GetHashCode()' có ý nghĩa. Xem liên kết trong bài đăng của tôi: http://stackoverflow.com/questions/74032/whats-the-recommended-best-practice-for-using-iequalitycomparert/4679491#4679491 –
** KHÔNG ** sử dụng 'obj mặc định này .GetHashCode() 'dự phòng. So sánh ví dụ: '(s1, s2) => s1.ToLower(). Bằng (s2.ToLower())' trả về 'true' trong đó' string.GetHashCode() 'mặc định trả về false! – ulrichb