มันเป็นไปได้
tl; dr - คุณสามารถแทนที่เมธอด get-only ด้วย setter หากคุณต้องการ มันเป็นเพียงแค่:
สร้างnew
คุณสมบัติที่มีทั้ง a get
และ a set
โดยใช้ชื่อเดียวกัน
ถ้าคุณไม่ทำอะไรอย่างอื่นget
วิธีเก่าจะยังคงถูกเรียกเมื่อคลาสที่ได้รับนั้นถูกเรียกผ่านประเภทฐาน ในการแก้ไขปัญหานี้ให้เพิ่มabstract
เลเยอร์กลางที่ใช้override
กับget
วิธีเก่าเพื่อบังคับให้ส่งคืนget
ผลลัพธ์ของวิธีการใหม่
สิ่งนี้ช่วยให้เราสามารถแทนที่คุณสมบัติด้วยget
/ set
แม้ว่าพวกเขาจะขาดหนึ่งในคำจำกัดความฐานของพวกเขา
เป็นโบนัสคุณสามารถเปลี่ยนประเภทผลตอบแทนได้หากต้องการ
หากคำจำกัดความฐานคือget
- เท่านั้นคุณสามารถใช้ประเภทผลตอบแทนที่ได้รับมากขึ้น
หากคำจำกัดความพื้นฐานคือset
- เพียงอย่างเดียวคุณสามารถส่งคืนชนิดที่ได้รับน้อยลง
ถ้าคำจำกัดความพื้นฐานเป็นอยู่แล้วget
/ set
ดังนั้น:
ในทุกกรณีคุณสามารถใช้ประเภทผลตอบแทนเดิมได้หากต้องการ ตัวอย่างด้านล่างใช้ประเภทผลตอบแทนเดียวกันเพื่อความเรียบง่าย
สถานการณ์: get
คุณสมบัติที่มีอยู่แล้วเท่านั้น
คุณมีโครงสร้างคลาสที่คุณไม่สามารถแก้ไขได้ อาจเป็นเพียงคลาสเดียวหรือเป็นแผนผังการสืบทอดที่มีอยู่แล้ว คุณต้องการเพิ่มset
วิธีการในคุณสมบัติ แต่ไม่สามารถทำได้
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; } }
}
ปัญหา: ไม่สามารถoverride
ใช้get
ร่วมกับget
/set
คุณต้องการoverride
ด้วยget
/ a set
คุณสมบัติ แต่มันจะไม่รวบรวม
public class C : B
{
private int _x;
public override int X
{
get { return _x; }
set { _x = value; } // Won't compile
}
}
วิธีแก้ไข: ใช้abstract
เลเยอร์ระดับกลาง
แม้ว่าคุณจะไม่สามารถoverride
ใช้ a get
/ set
property โดยตรงแต่คุณสามารถ :
สร้าง a new
get
/ set
property ที่มีชื่อเดียวกัน
override
get
วิธีเก่าที่มี accessor กับget
วิธีการใหม่เพื่อให้แน่ใจว่าสอดคล้อง
ดังนั้นก่อนอื่นให้คุณเขียนabstract
เลเยอร์กลาง:
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; }
}
จากนั้นคุณเขียนชั้นเรียนที่จะไม่รวบรวมก่อนหน้านี้ มันจะคอมไพล์ในครั้งนี้เพราะคุณไม่ได้อยู่override
ในget
คุณสมบัติ - เพียงอย่างเดียว คุณจะแทนที่ด้วยnew
คำหลักแทน
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; } }
}
ผลลัพธ์: ทุกอย่างใช้งานได้!
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.
ทุกอย่างยังคงทำงานได้ตามที่ตั้งใจไว้เมื่อดูD
เป็นหนึ่งในชั้นเรียนฐานเช่นหรือA
B
แต่สาเหตุที่ใช้งานอาจไม่ชัดเจนนัก
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.
อย่างไรก็ตามนิยามคลาสพื้นฐานของget
ยังคงถูกแทนที่ในที่สุดโดยนิยามของคลาสที่ได้รับget
ดังนั้นจึงยังคงสอดคล้องกันอย่างสมบูรณ์
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.
อภิปรายผล
วิธีนี้ช่วยให้คุณสามารถเพิ่มset
วิธีการget
- คุณสมบัติเท่านั้น คุณยังสามารถใช้เพื่อทำสิ่งต่าง ๆ เช่น:
เปลี่ยนคุณสมบัติใด ๆ ให้เป็นget
-only set
-only หรือget
-and- set
property โดยไม่คำนึงถึงสิ่งที่อยู่ในคลาสฐาน
เปลี่ยนชนิดการส่งคืนของเมธอดในคลาสที่ได้รับ
ข้อเสียเปรียบหลักคือมีการเข้ารหัสที่ต้องทำและพิเศษabstract class
ในแผนผังการสืบทอด สิ่งนี้อาจสร้างความรำคาญให้กับคอนสตรัคเตอร์ที่รับพารามิเตอร์เนื่องจากสิ่งเหล่านั้นจะต้องคัดลอก / วางในเลเยอร์กลาง