Có thể
tl; dr - Bạn có thể ghi đè phương thức chỉ lấy bằng setter nếu muốn. Về cơ bản chỉ là:
Tạo một thuộc newtính có cả a getvà aset sử dụng cùng tên.
Nếu bạn không làm gì khác, thì cũ get phương thức sẽ vẫn được gọi khi lớp dẫn xuất được gọi thông qua kiểu cơ sở của nó. Để khắc phục điều này, hãy thêm một abstractlớp trung gian sử dụng phương thức overridecũ getđể buộc nó trả về getkết quả của phương thức mới .
Điều này cho phép chúng tôi ghi đè các thuộc tính với get/set ngay cả khi chúng thiếu một trong định nghĩa cơ sở của chúng.
Là một phần thưởng, bạn cũng có thể thay đổi loại trả lại nếu bạn muốn.
Nếu định nghĩa cơ sở là get-only, thì bạn có thể sử dụng loại trả về có nguồn gốc nhiều hơn.
Nếu định nghĩa cơ sở là set-only, thì bạn có thể cho chúng tôi loại trả về ít dẫn xuất hơn.
Nếu định nghĩa cơ sở đã get/set , thì:
Trong mọi trường hợp, bạn có thể giữ cùng kiểu trả về nếu muốn. Các ví dụ dưới đây sử dụng cùng loại trả về cho đơn giản.
Tình huống: Có từ trước get Tài sản
Bạn có một số cấu trúc lớp mà bạn không thể sửa đổi. Có thể đó chỉ là một lớp hoặc là cây thừa kế có sẵn. Dù thế nào đi nữa, bạn muốn thêm một setphương thức vào một thuộc tính, nhưng không thể.
public abstract class A // Pre-existing class; can't modify
{
public abstract int X { get; } // You want a setter, but can't add it.
}
public class B : A // Pre-existing class; can't modify
{
public override int X { get { return 0; } }
}
Vấn đề: Không thể overridecác get-only với get/set
Bạn muốn overridevới một get/ setproperty, nhưng nó sẽ không được biên dịch.
public class C : B
{
private int _x;
public override int X
{
get { return _x; }
set { _x = value; } // Won't compile
}
}
Giải pháp: Sử dụng một abstractlớp trung gian
Trong khi bạn không thể trực tiếp overridevới get/ settài sản, bạn có thể :
Tạo một new get/ thuộc settính có cùng tên.
overridegetphương pháp cũ với một người truy cập vào getphương thức mới để đảm bảo tính nhất quán.
Vì vậy, đầu tiên bạn viết abstractlớp trung gian:
public abstract class C : B
{
// Seal off the old getter. From now on, its only job
// is to alias the new getter in the base classes.
public sealed override int X { get { return this.XGetter; } }
protected abstract int XGetter { get; }
}
Sau đó, bạn viết lớp không biên dịch trước đó. Nó sẽ biên dịch lần này vì bạn không thực sự overridelà gettài sản chung; thay vào đó, bạn đang thay thế nó bằng newtừ khóa.
public class D : C
{
private int _x;
public new virtual int X { get { return this._x; } set { this._x = value; } }
// Ensure base classes (A,B,C) use the new get method.
protected sealed override int XGetter { get { return this.X; } }
}
Kết quả: Mọi thứ đều hoạt động!
Rõ ràng, điều này làm việc như dự định cho D.
var test = new D();
Print(test.X); // Prints "0", the default value of an int.
test.X = 7;
Print(test.X); // Prints "7", as intended.
Mọi thứ vẫn hoạt động như dự định khi xem Dnhư một trong các lớp cơ sở của nó, ví dụ Ahoặc B. Nhưng, lý do tại sao nó hoạt động có thể là một chút ít rõ ràng.
var test = new D() as B;
//test.X = 7; // This won't compile, because test looks like a B,
// and B still doesn't provide a visible setter.
Tuy nhiên, định nghĩa của lớp cơ sở getcuối cùng vẫn bị ghi đè bởi định nghĩa của lớp dẫn xuất get, vì vậy nó vẫn hoàn toàn nhất quán.
var test = new D();
Print(test.X); // Prints "0", the default value of an int.
var baseTest = test as A;
Print(test.X); // Prints "7", as intended.
Thảo luận
Phương pháp này cho phép bạn thêm setcác phương thức vào getcác thuộc tính -only. Bạn cũng có thể sử dụng nó để làm những việc như:
Thay đổi bất kỳ thuộc tính nào thành thuộc tính get-only, set-only hoặc get-and- set, bất kể nó thuộc lớp cơ sở nào.
Thay đổi kiểu trả về của một phương thức trong các lớp dẫn xuất.
Những nhược điểm chính là có nhiều mã hóa hơn để làm và thêm abstract classvào trong cây thừa kế. Điều này có thể gây một chút khó chịu với các nhà xây dựng lấy tham số vì chúng phải được sao chép / dán trong lớp trung gian.