เพียงเพื่อให้แน่ใจว่าเราอยู่ในหน้าเดียวกันเมธอด "การซ่อน" คือเมื่อคลาสที่ได้รับกำหนดสมาชิกชื่อเดียวกันกับหนึ่งในคลาสพื้นฐาน (ซึ่งหากเป็นเมธอด / คุณสมบัติจะไม่ทำเครื่องหมายเสมือน / overridable ) และเมื่อมีการเรียกใช้จากอินสแตนซ์ของคลาสที่ได้รับใน "บริบทที่ได้รับ" สมาชิกที่ได้รับจะถูกใช้ในขณะที่ถ้ามีการเรียกใช้โดยอินสแตนซ์เดียวกันในบริบทของคลาสพื้นฐานนั้นจะใช้สมาชิกคลาสพื้นฐาน สิ่งนี้แตกต่างจากสมาชิก abstraction / overriding ที่สมาชิกคลาสพื้นฐานคาดว่าคลาสที่ได้รับเพื่อกำหนดการแทนที่และจากตัวดัดแปลงขอบเขต / การมองเห็นที่ "ซ่อน" สมาชิกจากผู้บริโภคที่อยู่นอกขอบเขตที่ต้องการ
คำตอบสั้น ๆ ว่าทำไมได้รับอนุญาตคือการไม่ทำเช่นนั้นจะบังคับให้นักพัฒนาซอฟต์แวร์ละเมิดหลักการสำคัญหลายประการของการออกแบบเชิงวัตถุ
นี่คือคำตอบอีกต่อไป; ก่อนอื่นให้พิจารณาโครงสร้างคลาสต่อไปนี้ในจักรวาลทางเลือกโดยที่ C # ไม่อนุญาตให้ซ่อนสมาชิก:
public interface IFoo
{
string MyFooString {get;}
int FooMethod();
}
public class Foo:IFoo
{
public string MyFooString {get{return "Foo";}}
public int FooMethod() {//incredibly useful code here};
}
public class Bar:Foo
{
//public new string MyFooString {get{return "Bar";}}
}
เราต้องการยกเลิกการคอมเม้นท์สมาชิกใน Bar และอนุญาตให้ Bar ให้ MyFooString อื่น อย่างไรก็ตามเราไม่สามารถทำได้เพราะจะเป็นการละเมิดข้อห้ามทางเลือกอื่น ๆ ในการซ่อนสมาชิก ตัวอย่างนี้เป็นตัวอย่างที่สมบูรณ์สำหรับข้อบกพร่องและเป็นตัวอย่างสำคัญของสาเหตุที่คุณอาจต้องการแบน เช่นเอาต์พุตคอนโซลใดที่คุณจะได้รับถ้าคุณทำสิ่งต่อไปนี้
Bar myBar = new Bar();
Foo myFoo = myBar;
IFoo myIFoo = myFoo;
Console.WriteLine(myFoo.MyFooString);
Console.WriteLine(myBar.MyFooString);
Console.WriteLine(myIFoo.MyFooString);
ฉันไม่แน่ใจว่าคุณจะได้รับ "ฟู" หรือ "บาร์" ในบรรทัดสุดท้ายนั้นหรือไม่ คุณจะได้รับ "Foo" สำหรับบรรทัดแรกและ "บาร์" เป็นครั้งที่สองแม้ว่าตัวแปรทั้งสามนั้นจะอ้างอิงอินสแตนซ์เดียวกันกับสถานะเดียวกันทั้งหมด
ดังนั้นผู้ออกแบบภาษาในเอกภพทางเลือกของเราจึงไม่สนับสนุนรหัสที่ไม่ดีอย่างเห็นได้ชัดนี้โดยป้องกันการซ่อนคุณสมบัติ ตอนนี้คุณในฐานะ coder มีความต้องการที่แท้จริงในการทำสิ่งนี้ คุณจะหลีกเลี่ยงข้อ จำกัด ได้อย่างไร วิธีหนึ่งคือตั้งชื่อคุณสมบัติของบาร์แตกต่างกัน:
public class Bar:Foo
{
public string MyBarString {get{return "Bar";}}
}
ถูกกฎหมายอย่างสมบูรณ์แบบ แต่มันไม่ใช่พฤติกรรมที่เราต้องการ ตัวอย่างของ Bar จะผลิต "Foo" สำหรับทรัพย์สิน MyFooString เสมอเมื่อเราต้องการให้มันผลิต "Bar" ไม่เพียง แต่เราต้องรู้ว่า IFoo ของเราเป็นบาร์โดยเฉพาะเรายังต้องรู้จักการใช้ accessor ที่แตกต่างกัน
นอกจากนี้เรายังสามารถลืมความสัมพันธ์ระหว่างพ่อแม่กับลูกและใช้อินเทอร์เฟซได้โดยตรง:
public class Bar:IFoo
{
public string MyFooString {get{return "Bar";}}
public int FooMethod() {...}
}
สำหรับตัวอย่างง่ายๆนี้มันเป็นคำตอบที่สมบูรณ์แบบตราบใดที่คุณใส่ใจว่า Foo และ Bar เป็นทั้ง IFoos โค้ดการใช้งานที่ตัวอย่างสองตัวอย่างไม่สามารถรวบรวมได้เนื่องจาก Bar ไม่ใช่ Foo และไม่สามารถกำหนดเช่นนี้ได้ อย่างไรก็ตามหาก Foo มีวิธีที่มีประโยชน์ "FooMethod" ที่แถบนั้นต้องการตอนนี้คุณจะไม่สามารถสืบทอดวิธีนั้นได้ คุณอาจต้องโคลนรหัสในบาร์หรือสร้างโฆษณา:
public class Bar:IFoo
{
public string MyFooString {get{return "Bar";}}
private readonly theFoo = new Foo();
public int FooMethod(){return theFoo.FooMethod();}
}
นี่คือการแฮ็กที่เห็นได้ชัดและในขณะที่การใช้ภาษา OO บางอย่างมีค่ามากกว่านี้ แต่แนวคิดก็ผิด หากผู้บริโภคของบาร์จำเป็นที่จะต้องเปิดเผยการทำงานของ Foo, บาร์ควรจะฟูไม่ได้มีฟู
เห็นได้ชัดว่าถ้าเราควบคุม Foo เราสามารถทำให้มันเสมือนจริงแล้วแทนที่มัน นี่คือแนวปฏิบัติที่ดีที่สุดในจักรวาลปัจจุบันของเราเมื่อสมาชิกคาดว่าจะถูกแทนที่และจะถือในจักรวาลสำรองใด ๆ ที่ไม่อนุญาตให้มีการซ่อน:
public class Foo:IFoo
{
public virtual string MyFooString {get{return "Foo";}}
//...
}
public class Bar:Foo
{
public override string MyFooString {get{return "Bar";}}
}
ปัญหานี้คือการเข้าถึงสมาชิกเสมือนอยู่ภายใต้ประทุนค่อนข้างแพงกว่าในการดำเนินการและโดยทั่วไปคุณต้องการทำเมื่อคุณต้องการเท่านั้น อย่างไรก็ตามการขาดการซ่อนกำลังบังคับให้คุณมองโลกในแง่ร้ายเกี่ยวกับสมาชิกที่ coder อื่นที่ไม่ได้ควบคุมซอร์สโค้ดของคุณอาจต้องการนำมาใช้ใหม่ "แนวปฏิบัติที่ดีที่สุด" สำหรับชั้นเรียนที่ไม่มีการปิดผนึกจะทำให้ทุกอย่างเสมือนจริงเว้นแต่ว่าคุณไม่ต้องการให้เป็นเช่นนั้นโดยเฉพาะ นอกจากนี้ยังไม่ให้พฤติกรรมที่แน่นอนในการซ่อน สตริงจะเป็น "บาร์" เสมอหากอินสแตนซ์คือบาร์ บางครั้งมันมีประโยชน์อย่างแท้จริงในการใช้เลเยอร์ของข้อมูลสถานะที่ซ่อนอยู่ตามระดับของการสืบทอดที่คุณใช้งานอยู่
โดยสรุปการอนุญาติให้สมาชิกซ่อนตัวได้น้อยกว่าความชั่วร้ายเหล่านี้ โดยทั่วไปแล้วจะไม่นำไปสู่การทารุณที่เลวร้ายกว่าที่กระทำกับหลักการเชิงวัตถุมากกว่าการยอมให้ทำ