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 new
tính có cả a get
và 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 abstract
lớp trung gian sử dụng phương thức override
cũ get
để buộc nó trả về get
kế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 set
phươ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ể override
các get
-only với get
/set
Bạn muốn override
với một get
/ set
property, 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 abstract
lớp trung gian
Trong khi bạn không thể trực tiếp override
với get
/ set
tài sản, bạn có thể :
Tạo một new
get
/ thuộc set
tính có cùng tên.
override
get
phương pháp cũ với một người truy cập vào get
phương thức mới để đảm bảo tính nhất quán.
Vì vậy, đầu tiên bạn viết abstract
lớ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ự override
là get
tài sản chung; thay vào đó, bạn đang thay thế nó bằng new
từ 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 D
như một trong các lớp cơ sở của nó, ví dụ A
hoặ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ở get
cuố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 set
các phương thức vào get
cá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 class
và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.