Nạp chồng toán tử (toán tử nạp chồng) trong C# Đăng bởi Show - 09/09/2019liên kết Hướng dẫn tự học lập trình C# toàn tập Nạp chồng toán tử (nạp chồng toán tử) trong C# Nạp chồng toán tử (toán tử nạp chồng) trong C# có khả năng định nghĩa lại hoạt động của một số toán tử để có thể áp dụng nó với các đối tượng của lớp bạn định nghĩa. Nếu bạn đã biết C++, bạn sẽ rất nhanh chóng bắt được chồng toán tử trong C#. Tuy nhiên, nếu bạn xuất phát từ Java hoặc Visual Basic, đây có thể là vấn đề mới Bài học này sẽ giúp bạn nắm bắt được ý nghĩa của việc nạp chồng toán tử và cách thực hiện trong C# NỘI DUNG CỦA BẢNG Nạp tiền điện tử trong C#Bộ sưu tập các thuật toánĐối với các kiểu dữ liệu, C# định nghĩa sẵn một số phép toán như phép toán học, phép toán so sánh, phép toán tăng giảm. Đối với kiểu chuỗi, như chúng ta đã biết, được phép tính toán cộng gộp sẵn có Tuy nhiên, các kiểu dữ liệu (lớp) do người dùng định nghĩa lại không thể sử dụng ngay các phép toán đó được Ví dụ, nếu người dùng định nghĩa kiểu số phức, phép toán cơ bản trên kiểu số phức hợp lại không thể thực hiện được ngay, mặc dù về mặt toán học thì phép tính toán đối với kiểu số không có gì khác biệt với kiểu số Để giải quyết các vấn đề tương tự, C# cho phép nạp chồng toán tử, tức là cho phép định nghĩa lại các phép toán đã có với kiểu dữ liệu do người dùng xây dựng xây dựng Nạp chồng phương thức (nạp chồng phương thức) cùng với nạp chồng toán tử (nạp chồng toán tử) là hai đối tượng thuộc về nguyên lý đa hình tĩnh (đa hình tĩnh) Cách nạp chồng toán tử trong C#Hãy cùng thực hiện và phân tích ví dụ sau để hiểu cách nạp chồng toán. Chú ý xem xét cú pháp nạp đối với mỗi toán tử using System; namespace P01_OperatorOverload { /// <summary> /// lớp biểu diễn hình hộp /// </summary> internal class Box { public double Length { get; set; } public double Breadth { get; set; } public double Height { get; set; } public Box() { } public Box(double length, double breadth, double height) { Length = length; Breadth = breadth; Height = height; } /// <summary> /// tính thể tích khối hộp /// </summary> public double Volume => Length * Breadth * Height; // nạp chồng phép cộng public static Box operator +(Box b, Box c) { Box box = new Box { Length = b.Length + c.Length, Breadth = b.Breadth + c.Breadth, Height = b.Height + c.Height }; return box; } // nạp chồng phép so sánh bằng public static bool operator ==(Box lhs, Box rhs) { bool status = false; if (lhs.Length == rhs.Length && lhs.Height == rhs.Height && lhs.Breadth == rhs.Breadth) { status = true; } return status; } // nạp chồng phép so sánh khác public static bool operator !=(Box lhs, Box rhs) { bool status = false; if (lhs.Length != rhs.Length || lhs.Height != rhs.Height || lhs.Breadth != rhs.Breadth) { status = true; } return status; } // nạp chồng phép so sánh nhỏ hơn public static bool operator <(Box lhs, Box rhs) { bool status = false; if (lhs.Length < rhs.Length && lhs.Height < rhs.Height && lhs.Breadth < rhs.Breadth) { status = true; } return status; } // nạp chồng phép so sánh lớn hơn public static bool operator >(Box lhs, Box rhs) { bool status = false; if (lhs.Length > rhs.Length && lhs.Height > rhs.Height && lhs.Breadth > rhs.Breadth) { status = true; } return status; } public override string ToString() { return string.Format("({0}, {1}, {2})", Length, Breadth, Height); } } internal class Program { private static void Main(string[] args) { Box Box1 = new Box(6, 7, 5); Box Box2 = new Box(12, 13, 10); Box Box3 = new Box(); Box Box4 = new Box(); /* phép cộng hai hình hộp cho ra hình hộp khác có kích thước * bằng tổng kích thước của hai hộp */ Box3 = Box1 + Box2; Console.WriteLine("Box 3: {0}", Box3.ToString()); Console.WriteLine("Volume of Box3 : {0}", Box3.Volume); // so sánh hai hình hộp if (Box1 > Box2) Console.WriteLine("Box1 lớn hơn Box2"); else Console.WriteLine("Box1 không lớn hơn Box2"); if (Box3 == Box4) Console.WriteLine("Box3 bằng Box4"); else Console.WriteLine("Box3 không bằng Box4"); Console.ReadKey(); } } } Trong ví dụ trên chúng ta đã thực hiện nạp chồng phép cộng (+), phép so sánh (bằng ==, khác. =, lớn hơn >, nhỏ hơn <) Cú pháp báo cáo này được tổng hợp lại dưới đây public static Box operator +(Box b, Box c) {...} public static bool operator ==(Box lhs, Box rhs) {...} public static bool operator !=(Box lhs, Box rhs) {...} public static bool operator <(Box lhs, Box rhs) {...} public static bool operator >(Box lhs, Box rhs) {...} Nếu để ý kỹ hơn nữa chúng ta thấy, đây đều là các phép toán nhị phân. Cách nạp các phép toán này có cùng một cú pháp Mỗi loại phép toán sẽ có cách tải riêng. Tuy nhiên, cú pháp chung là public static <return_type> operator <operator>(<parameters>) { .. } Các toán tử có thể nạp chồng: +, -, !, ~, ++, –, +, -, *, /, %, ==, !=, <, >, <=, >= Ngoài ra phép toán indexer còn là một phép toán có thể nạp chồng Một số lưu ý khi tải thực hiện tài khoản điện tửCác phép toán chia làm ba loại. đơn hạng (chỉ cần một toán hạng, như phép toán tăng ++, phép toán giảm –), nhị phân (cần hai toán hạng, như phép toán +,-,*,/), ternary (cần ba toán hạng, như phép . Do đó, khi nạp bất kỳ khoản thanh toán cho phép nào thì phải cung cấp đủ lượng tham số phù hợp. Ví dụ, khi nạp chồng phép toán nhị phân (như +, -) thì phải cấp 2 tham số như đã làm ở trên Phép toán tăng giảm (++, –) thuộc loại đơn nguyên nên trong danh sách tham số chỉ cần 1 tham số. Các phép toán này cũng không có giới hạn gì khi nạp chồng. With the example with Layer Box on public static Box operator ++ (Box b) { return new Box(b.Length++, b.Breadth++, b.Height++); } Các phép toán học (+, – *, /, %) không đặt ra giới hạn nào khi tải chồng. Bạn chỉ cần tuân thủ cú pháp đúng như trên đã được Bạn thậm chí có thể tải lên cùng một phép toán nhiều lần. Ví dụ, bạn hoàn toàn có thể nạp chồng phép + một lần nữa như sau public static Box operator +(Box b, double size) { return new Box(b.Length += size, b.Breadth += size, b.Height + size); } Ở đây bạn đã tải xuống hộp cộng cho phép với một số thực. Điều kiện cho phép nạp chồng nhiều lần là danh sách tham số của mỗi lần nạp chồng phải khác nhau Đối với các phép so sánh toán học, bạn phải thực hiện nạp cả cặp. Nghĩa là, nếu tải cả phép so sánh bằng == thì đồng thời phải tải cả phép so sánh khác. =; Các phép gán (+=, -=, v. v. ) không cho phép tải trực tiếp. Tuy nhiên, nếu bạn đã cho phép tải +,-, v. v. thì các phép toán này tự nhiên sẽ được tải lên. Ví dụ, nếu bạn đã nạp chồng phép cộng Box với 1 số như trên thì hoàn toàn có thể gọi lệnh var Box5 = Box4 += 5; // phép cộng gán với số Bộ chỉ mục toán học riêng cho phép có cách thực hiện nạp chồng riêng dưới đây Nạp chỉ mục toán học cấp phép trong C#Bộ lập chỉ mục là một phép toán giúp mã máy khách sử dụng đối tượng tương tự như khi sử dụng mảng. Indexer thường được sử dụng với các kiểu dữ liệu chứa trong nó một tập hợp dữ liệu (bộ sưu tập hoặc mảng). Trình lập chỉ mục giúp đơn giản hóa việc sử dụng ở mã máy khách Trước khi xem cú pháp nạp chỉ mục toán tử, hãy cùng thực hiện ví dụ sau namespace P02_IndexerOverload { using static System.Console; class Program { static void Main(string[] args) { var vector1 = new Vector(1, 2, 3); WriteLine($"vector 1: {vector1}"); ReadLine(); } } class Vector { private double[] _components; public Vector(int dimension) { _components = new double[dimension]; } public Vector(params double[] components) { _components = components; } public override string ToString() { return $"({string.Join(", ", _components)})"; } } } Ví dụ này xây dựng một lớp Vector đơn giản dành cho vector n-chiều. Cả vector được lưu trong một _components mảng riêng (mỗi phần tử của mảng là kích thước một chiều của vector). Lớp này có 2 quá tải cho hàm tạo, một cái nhận chiều làm tham số, một cái nhận mảng double làm tham số Bạn có muốn truy xuất giá trị từng chiều của vectơ này như truy xuất phần tử của mảng không? . v. , trong đó 0, 1, chỉ là chiều Cú pháp load indexerCú pháp cấp phép lập chỉ mục toán học cho thuộc tính gần giống của lớp, trong đó phải có ít nhất một trong hai phương thức get/set, dùng để trả lại giá trị và gán giá trị. Khác biệt duy nhất ở vị trí bộ lập chỉ mục bắt buộc sử dụng từ khóa public static Box operator +(Box b, Box c) {...} public static bool operator ==(Box lhs, Box rhs) {...} public static bool operator !=(Box lhs, Box rhs) {...} public static bool operator <(Box lhs, Box rhs) {...} public static bool operator >(Box lhs, Box rhs) {...}1 với cặp dấu ngoặc kép. Key shift must set in the dấu ngoặc kép________số 8_______ in which
Nạp chồng chỉ mục toán tử cho lớp VectorThêm đoạn mã sau vào lớp Vector public double this[int index] { get => (index < _components.Length) ? _components[index] : double.NaN; set { if (index < _components.Length) _components[index] = value; } } Cấu trúc kiến trúc này trông giống như một tài sản đầy đủ, ngoại trừ tên gọi public static Box operator +(Box b, Box c) {...} public static bool operator ==(Box lhs, Box rhs) {...} public static bool operator !=(Box lhs, Box rhs) {...} public static bool operator <(Box lhs, Box rhs) {...} public static bool operator >(Box lhs, Box rhs) {...}4. Đoạn mã này đã thực hiện tải bộ chỉ mục toán tử cho lớp Vector Hoạt động logic của getter rất đơn giản. Nếu chỉ mục nhỏ hơn số phần tử của mảng thì trả về giá trị tương ứng với chỉ mục, nếu không thì trả về giá trị NaN (Không phải là số). Setter chỉ gán giá trị cho phần tử tương ứng của mảng Nếu phương thức get/set chỉ chứa một lệnh duy nhất thì có thể sử dụng cú pháp “body biểu thức” để rút gọn. Trong mã của getter ở trên chúng ta đã sử dụng cấu trúc này Nội dung biểu thức là một lối viết xuất hiện từ C# 6. if body of the method only contain a command duy nhất có thể sử dụng cấu trúc như sau để viết Bây giờ bạn có thể truy xuất từng chiều của vector như sau static void Main(string[] args) { var vector1 = new Vector(1, 2, 3); WriteLine($"vector 1: {vector1}"); var x = vector1[0]; var y = vector1[1]; var z = vector1[2]; WriteLine($"Vector components: x = {x}, y = {y}, z = {z}"); vector1[2] = 30; vector1[1] = 20; vector1[0] = 10; WriteLine($"vector 1: {vector1}"); ReadLine(); } Dưới đây là mã đầy đủ của ví dụ trên public static Box operator +(Box b, Box c) {...} public static bool operator ==(Box lhs, Box rhs) {...} public static bool operator !=(Box lhs, Box rhs) {...} public static bool operator <(Box lhs, Box rhs) {...} public static bool operator >(Box lhs, Box rhs) {...}0 Kết luậnBài học này đã hướng dẫn các bạn làm quen với việc nạp chồng toán tử cho lớp trong C#. Bạn có thể thấy, thực hiện nạp chồng toán tử trong C# rất đơn giản |