มันเป็นไปได้
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/ setproperty โดยตรงแต่คุณสามารถ :
สร้าง a new get/ setproperty ที่มีชื่อเดียวกัน
overridegetวิธีเก่าที่มี 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- setproperty โดยไม่คำนึงถึงสิ่งที่อยู่ในคลาสฐาน
เปลี่ยนชนิดการส่งคืนของเมธอดในคลาสที่ได้รับ
ข้อเสียเปรียบหลักคือมีการเข้ารหัสที่ต้องทำและพิเศษabstract classในแผนผังการสืบทอด สิ่งนี้อาจสร้างความรำคาญให้กับคอนสตรัคเตอร์ที่รับพารามิเตอร์เนื่องจากสิ่งเหล่านั้นจะต้องคัดลอก / วางในเลเยอร์กลาง