ความแตกต่างระหว่างการทำเงาและการแทนที่เมธอดใน C # คืออะไร?
ความแตกต่างระหว่างการทำเงาและการแทนที่เมธอดใน C # คืออะไร?
คำตอบ:
มรดกดี ...
สมมติว่าคุณมีคลาสนี้:
class A {
public int Foo(){ return 5;}
public virtual int Bar(){return 5;}
}
class B : A{
public new int Foo() { return 1;} //shadow
public override int Bar() {return 1;} //override
}
จากนั้นเมื่อคุณเรียกสิ่งนี้:
A clA = new A();
B clB = new B();
Console.WriteLine(clA.Foo()); // output 5
Console.WriteLine(clA.Bar()); // output 5
Console.WriteLine(clB.Foo()); // output 1
Console.WriteLine(clB.Bar()); // output 1
//now let's cast B to an A class
Console.WriteLine(((A)clB).Foo()); // output 5 <<<-- shadow
Console.WriteLine(((A)clB).Bar()); // output 1
สมมติว่าคุณมีคลาสพื้นฐานและคุณใช้คลาสพื้นฐานในโค้ดทั้งหมดของคุณแทนที่จะเป็นคลาสที่สืบทอดมาและคุณใช้เงามันจะส่งคืนค่าที่คลาสฐานส่งกลับแทนที่จะทำตามโครงสร้างการสืบทอดของประเภทจริงของอ็อบเจ็กต์
หวังว่าฉันจะเข้าใจ :)
Shadowing เป็นคำพูดของ VB สำหรับสิ่งที่เราอ้างถึงว่าซ่อนอยู่ใน C #
มักจะซ่อนตัวอยู่ (แชโดว์ใน VB) และที่สำคัญมีการแสดงให้เห็นว่าในคำตอบโดยStormenet
วิธีการเสมือนถูกแสดงให้เห็นว่าถูกแทนที่โดยคลาสย่อยและการเรียกใช้เมธอดนั้นแม้ในประเภทซุปเปอร์คลาสหรือจากโค้ดภายในของซูเปอร์คลาสจะเรียกการใช้งานทดแทนจากคลาสย่อย
จากนั้นวิธีการที่เป็นรูปธรรมจะปรากฏขึ้น (วิธีที่ไม่ถูกทำเครื่องหมายว่าเสมือนหรือนามธรรม) ถูกซ่อนโดยใช้new
คำสำคัญเมื่อกำหนดวิธีการที่มีลายเซ็นที่เหมือนกันบนคลาสย่อย ในกรณีนี้เมื่อเมธอดถูกเรียกใช้ในประเภทซุปเปอร์คลาสที่ใช้การใช้งานดั้งเดิมการใช้งานใหม่จะพร้อมใช้งานบนคลาสย่อยเท่านั้น
อย่างไรก็ตามสิ่งที่มักจะพลาดคือสามารถซ่อนวิธีเสมือนได้
class A
{
public virtual void DoStuff() { // original implementation }
}
class B : A
{
public new void DoStuff() { //new implementation }
}
B b = new B();
A a = b;
b.DoStuff(); //calls new implementation
a.DoStuff(); //calls original implementation.
หมายเหตุในตัวอย่างข้างต้น DoStuff กลายเป็นรูปธรรมและไม่สามารถลบล้างได้ อย่างไรก็ตามยังสามารถใช้ทั้งคำหลักvirtual
และnew
คำหลักร่วมกันได้
class A
{
public virtual void DoStuff() { // original implementation }
}
class B : A
{
public new virtual void DoStuff() { //new implementation }
}
class C : B
{
public override void DoStuff() { //replacement implementation }
}
C c = new C();
B b = c;
A a = b;
c.DoStuff(); //calls replacement implementation
b.DoStuff(); //calls replacement implementation
a.DoStuff(); //calls original implementation.
โปรดทราบว่าแม้วิธีการทั้งหมดที่เกี่ยวข้องจะเป็นเสมือนการแทนที่บน C จะไม่มีผลต่อวิธีการเสมือนบน A เนื่องจากการใช้new
ใน B จะซ่อนการใช้งาน A
แก้ไข:มีการระบุไว้ในความคิดเห็นของคำตอบนี้ว่าข้างต้นอาจเป็นอันตรายหรืออย่างน้อยก็ไม่มีประโยชน์อย่างยิ่ง ฉันจะบอกว่าใช่มันอาจเป็นอันตรายและจะอยู่ที่นั่นถ้ามันมีประโยชน์
โดยเฉพาะอย่างยิ่งคุณอาจประสบปัญหาทุกประเภทหากคุณเปลี่ยนตัวปรับแต่งความสามารถในการเข้าถึงด้วย ตัวอย่างเช่น:-
public class Foo
{
internal Foo() { }
protected virtual string Thing() { return "foo"; }
}
public class Bar : Foo
{
internal new string Thing() { return "bar"; }
}
ไปยังทายาทภายนอกของBar
, Foo
ของการดำเนินงานของสิ่งที่ () ยังคง accesible และ overridable ทั้งหมดถูกกฎหมายและสามารถอธิบายได้ตามกฎประเภท. NET ไม่เคยไม่ได้ตั้งใจเลยทีเดียว
ฉันได้โพสต์คำตอบนี้เพื่อทำความเข้าใจให้ลึกซึ้งยิ่งขึ้นว่าสิ่งต่างๆทำงานอย่างไรไม่ใช่คำแนะนำของเทคนิคที่สามารถใช้ได้อย่างอิสระ
Shadowing เป็นแนวคิด VB.NET ในภาษา C # Shadowing เรียกว่าการซ่อน มันซ่อนเมธอดคลาสที่ได้รับ ทำได้โดยใช้คำหลัก 'ใหม่'
คีย์เวิร์ด Override ใช้เพื่อจัดเตรียมการนำเมธอดคลาสพื้นฐานไปใช้ใหม่โดยสมบูรณ์ (ซึ่งมีเครื่องหมาย 'เสมือน') ในคลาสที่ได้รับ
โดยทั่วไปหากคุณมีสิ่งที่ต้องการด้านล่าง
Class A
{
}
Class B:A
{
}
A a = new B();
วิธีการใด ๆ ที่คุณเรียกใช้กับวัตถุ 'a' จะถูกสร้างขึ้นในประเภทของ 'a' (ในที่นี้คือประเภท 'A') แต่ถ้าคุณใช้วิธีการเดียวกันในคลาส B ที่มีอยู่แล้วในคลาส A คอมไพเลอร์จะ เตือนคุณให้ใช้คำหลัก "ใหม่" หากคุณใช้ "ใหม่" คำเตือนจะหายไป นอกเหนือจากนี้ไม่มีความแตกต่างระหว่างการใช้ "ใหม่" หรือไม่ใช้ในคลาสที่สืบทอดมา
ในบางสถานการณ์คุณอาจต้องเรียกใช้เมธอดของคลาสอ้างอิงที่อินสแตนซ์เฉพาะถืออยู่ในขณะนั้นแทนที่จะเรียกเมธอดในประเภทอ็อบเจ็กต์ ในกรณีข้างต้นการอ้างอิงถือเป็น 'B' แต่ประเภทคือ 'A' ดังนั้นหากคุณต้องการให้การเรียกใช้เมธอดเกิดขึ้นที่ 'B' คุณจึงใช้ Virtual และแทนที่เพื่อให้บรรลุสิ่งนี้
หวังว่านี่จะช่วยได้ ...
Daniel Sandeep
หากมีบางกรณีที่คุณไม่สามารถแก้ไขเนื้อหาของคลาสได้สมมติว่าA
คุณต้องการใช้วิธีการบางอย่างพร้อมกับคุณมีวิธีการที่ชื่อเป็นเรื่องธรรมดาคุณสามารถใช้วิธีการของคุณเองโดยใช้new
คีย์เวิร์ด
ประเด็นสำคัญคือการใช้ว่าทั้งการอ้างอิงและวัตถุต้องเป็นประเภทเดียวกัน
class A
{
public void Test()
{
Console.WriteLine("base");
}
}
class B : A
{
public new void Test()
{
Console.WriteLine("sub");
}
public static void Main(string[] args)
{
A a = new A();
B aa = new B();
a.Test();
aa.Test();
}
}