Chúng tôi đã phân tích các điểm đặc biệt của cấu trúc trong khuôn khổ .NET đại diện cho Loại giá trị khi so sánh các đối tượng theo giá trị - ví dụ của cấu trúc.
Bây giờ, tôi sẽ mô tả quá trình này trên một ví dụ cụ thể để kiểm tra xem nó có cho phép chúng tôi xác định việc sử dụng so sánh đối tượng theo giá trị nói chung hay không và do đó, để đơn giản hóa một mẫu so sánh các đối tượng theo giá trị - các cá thể lớp đại diện cho tham chiếu các loại.
Cấu trúc PersonStruct:
using System; namespace HelloEquatable { public struct PersonStruct : IEquatable<PersonStruct>, IEquatable<PersonStruct?> { private static int GetHashCodeHelper(int[] subCodes) { int result = subCodes[0]; for (int i = 1; i < subCodes.Length; i++) result = unchecked(result * 397) ^ subCodes[i]; return result; } private static string NormalizeName(string name) => name?.Trim() ?? string.Empty; private static DateTime? NormalizeDate(DateTime? date) => date?.Date; public string FirstName { get; } public string LastName { get; } public DateTime? BirthDate { get; } public PersonStruct(string firstName, string lastName, DateTime? birthDate) { this.FirstName = NormalizeName(firstName); this.LastName = NormalizeName(lastName); this.BirthDate = NormalizeDate(birthDate); } public override int GetHashCode() => GetHashCodeHelper( new int[] { this.FirstName.GetHashCode(), this.LastName.GetHashCode(), this.BirthDate.GetHashCode() } ); public static bool Equals(PersonStruct first, PersonStruct second) => first.BirthDate == second.BirthDate && first.FirstName == second.FirstName && first.LastName == second.LastName; public static bool operator ==(PersonStruct first, PersonStruct second) => Equals(first, second); public static bool operator !=(PersonStruct first, PersonStruct second) => !Equals(first, second); public bool Equals(PersonStruct other) => Equals(this, other); public static bool Equals(PersonStruct? first, PersonStruct? second) => first == second; // Alternate version: //public static bool Equals(PersonStruct? first, PersonStruct? second) => // first.HasValue == second.HasValue && // ( // !first.HasValue || Equals(first.Value, second.Value) // ); public bool Equals(PersonStruct? other) => this == other; // Alternate version: //public bool Equals(PersonStruct? other) => // other.HasValue && Equals(this, other.Value); public override bool Equals(object obj) => (obj is PersonStruct) && Equals(this, (PersonStruct)obj); // Alternate version: //public override bool Equals(object obj) => // obj != null && // this.GetType() == obj.GetType() && // Equals(this, (PersonStruct)obj); } }
Như bạn có thể thấy, ví dụ này nhỏ hơn và dễ dàng hơn theo cấu trúc, vì các phiên bản của cấu trúc không rỗng và không thể kế thừa từ cấu trúc do người dùng xác định. Chúng ta đã thảo luận về các đặc thù để triển khai so sánh theo giá trị cho các trường hợp lớp trong bài viết trước của tôi.
Ngoài ra, chúng tôi đã xác định các trường để so sánh đối tượng cũng như triển khai phương thức GetHashCode ().
Các phương pháp và toán tử so sánh đã được thực hiện theo thứ tự sau:
- Để so sánh hai trường hợp cấu trúc, chúng tôi đã triển khai phương thức tĩnh PersonStruct.Equals (PersonStruct, PersonStruct). Chúng tôi sẽ sử dụng phương pháp này như một phương pháp so sánh tham chiếu khi thực hiện các phương pháp và toán tử khác. Ngoài ra, nó có thể được áp dụng để so sánh các trường hợp của cấu trúc trong các ngôn ngữ không hỗ trợ toán tử.
- Các toán tử PersonStruct. ==(PersonStruct, PersonStruct) và PersonStruct.! =(PersonStruct, PersonStruct) cũng đã được triển khai. Cần lưu ý rằng trình biên dịch C # có những đặc điểm sau:
- Bạn có thể so sánh với các toán tử được nạp chồng T. ==(T, T) và T.! =(T, T) trong Nullable (Trong số T)
- Trước khi kiểm tra bình đẳng giá trị, trình biên dịch có thể xác minh xem các bản sao của cấu trúc có giá trị hợp lệ hay không. Ngoài ra, trình biên dịch không bao bọc các phiên bản của cấu trúc vào các đối tượng.
- Do đó, việc so sánh các phiên bản của cấu trúc Nullable (Of T) với một giá trị nullable chưa được định kiểu dẫn đến việc gọi các toán tử ==(T, T) hoặc T.! =(T, T), trong khi so sánh các phiên bản của Nullable ( Cấu trúc của T) không có các toán tử được nạp chồng T. ==(T, T) và T.! =(T, T) dẫn đến việc gọi các toán tử Đối tượng. ==(Đối tượng, Đối tượng) hoặc Đối tượng.! =(Đối tượng, Đối tượng) và kết quả là trong việc gói một thể hiện vào đối tượng.
- Phương thức PersonStruct.Equals (PersonStruct) (triển khai IEquatable (Of PersonStruct)) đã được triển khai bằng cách gọi phương thức PersonStruct.Equals (PersonStruct, PersonStruct).
- Để tránh gói các trường hợp của cấu trúc vào các đối tượng, khi chúng ta có một hoặc hai trường hợp Nullable (Of PersonStruct), có thể triển khai các phương pháp sau:
- PersonStruct.Equals (PersonStruct ?, PersonStruct?), dưới dạng lệnh gọi của toán tử PersonStruct. ==(PersonStruct, PersonStruct), được sử dụng để tránh gói các trường hợp cấu trúc của cả hai đối số vào các đối tượng và gọi Object.Equals ( Đối tượng, Đối tượng) phương thức nếu ít nhất một trong các đối số là thể hiện Nullable (Of PersonStruct). Ngoài ra, bạn có thể sử dụng phương pháp này để so sánh các trường hợp Nullable (Of PersonStruct) trong các ngôn ngữ không hỗ trợ toán tử. Trong đoạn mã, bạn có thể tìm thấy các nhận xét giải thích cách thực hiện phương pháp này nếu trình biên dịch C # không thể sử dụng các toán tử T. ==(T, T) và T.! =(T, T) cho các toán tử Nullable (Of T) đối số.
- PersonStruct.Equals (PersonStruct?) - việc triển khai giao diện IEquatable (Of PersonStruct?) được sử dụng để tránh gói các đối số Nullable (Of PersonStruct) vào các đối tượng và gọi phương thức PersonStruct.Equals (Object). Nó được triển khai dưới dạng lời gọi của toán tử PersonStruct. ==(PersonStruct, PersonStruct) với mã được chú thích để sử dụng các toán tử T. ==(T, T) và T.! =(T, T) cho Nullable (Of T ) đối số.
- PersonStruct.Equals (Đối tượng) - ghi đè phương thức Object.Equals (Đối tượng). Nó được triển khai bằng cách kiểm tra tính tương thích của kiểu đối số với kiểu của đối tượng hiện tại bằng cách sử dụng toán tử is bằng cách truyền đối số tới PersonStruct và gọi PersonStruct.Equals (PersonStruct, PersonStruct).
Ghi chú:
- Việc triển khai giao diện IEquatable (Of PersonStruct?) - IEquatable (Of Nullable (Of PersonStruct)) phục vụ cho việc hiển thị các vấn đề cụ thể trong nền tảng khi làm việc với các cấu trúc trong đó việc gói các phiên bản vào các đối tượng diễn ra nhanh hơn chúng ta mong đợi.
- Trong các dự án thực tế, với điều kiện là không cần thiết phải cải thiện hiệu suất, việc triển khai IEquatable (Of Nullable (Của T)) không áp dụng được vì lý do kiến trúc - chúng tôi không nên triển khai IEquatable đã nhập ở kiểu T cho bất kỳ kiểu nào.
- Nói chung, không cần thiết phải áp đảo mã bằng các cách tối ưu hóa khác nhau.
Đối với các cấu trúc, chúng ta có thể đạt được cách làm cho việc so sánh theo giá trị trở nên đơn giản và hiệu quả hơn nhiều bằng cách tránh kế thừa các cấu trúc do Người dùng xác định và cần kiểm tra các đối tượng trên null. Ngoài ra, chúng ta có thể theo dõi một logic mới hỗ trợ các đối số Nullable (Of T).
Trong ấn phẩm sắp tới của tôi, tôi sẽ tóm tắt những điểm sau:
- Khi thực hiện so sánh các đối tượng theo giá trị là một ý tưởng hay;
- Cách chúng tôi có thể đơn giản hóa việc triển khai so sánh theo giá trị cho các đối tượng - các cá thể lớp đại diện cho các loại tham chiếu.
Cũng đọc:
So sánh các đối tượng theo giá trị. Phần 1:Bắt đầu
So sánh các đối tượng theo giá trị. Phần 2:Ghi chú thực hiện của Phương pháp bình đẳng
So sánh các đối tượng theo giá trị. Phần 3:Các toán tử công bằng và bình đẳng theo loại cụ thể
So sánh các đối tượng theo giá trị. Phần 4:Toán tử kế thừa &so sánh
So sánh các đối tượng theo giá trị. Phần 5:Vấn đề Bình đẳng Cơ cấu