อะไรคือความแตกต่างระหว่างการประกาศวิธีการในประเภทฐาน " virtual
" แล้วแทนที่มันในประเภทลูกโดยใช้override
คำหลัก "" ซึ่งตรงข้ามกับการใช้new
คำหลัก "" เมื่อประกาศวิธีการจับคู่ในประเภทลูก
อะไรคือความแตกต่างระหว่างการประกาศวิธีการในประเภทฐาน " virtual
" แล้วแทนที่มันในประเภทลูกโดยใช้override
คำหลัก "" ซึ่งตรงข้ามกับการใช้new
คำหลัก "" เมื่อประกาศวิธีการจับคู่ในประเภทลูก
คำตอบ:
คำหลัก "ใหม่" ไม่ได้แทนที่มันหมายถึงวิธีการใหม่ที่ไม่เกี่ยวข้องกับวิธีการเรียนพื้นฐาน
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
public class Test
{
public static void Main ()
{
Foo test = new Bar ();
Console.WriteLine (test.DoSomething ());
}
}
สิ่งนี้จะพิมพ์เท็จหากคุณใช้แทนที่มันจะพิมพ์จริง
(รหัสฐานนำมาจาก Joseph Daigle)
ดังนั้นถ้าคุณกำลังทำ polymorphism จริงคุณควรแทนที่ ที่เดียวที่คุณต้องใช้ "new" คือเมื่อเมธอดไม่เกี่ยวข้องในทางใดทางหนึ่งกับเวอร์ชันคลาสพื้นฐาน
virtual
อยู่ในฐานและที่override
ได้มา? ทำไมมันมีอยู่? รหัสจะยังคงทำงานแม้ไม่มีnew
- ดังนั้นมันเป็นเพียงแค่การอ่านอย่างหมดจด?
ฉันมักพบสิ่งต่าง ๆ เช่นนี้เข้าใจได้ง่ายขึ้นด้วยรูปภาพ
อีกครั้งรับรหัสของ joseph daigle
public class Foo
{
public /*virtual*/ bool DoSomething() { return false; }
}
public class Bar : Foo
{
public /*override or new*/ bool DoSomething() { return true; }
}
ถ้าคุณเรียกรหัสเช่นนี้:
Foo a = new Bar();
a.DoSomething();
หมายเหตุ: สิ่งสำคัญคือวัตถุของเราเป็นจริงBar
แต่เราเก็บไว้ในตัวแปรประเภทFoo
(นี้คล้ายกับการคัดเลือกนักแสดง)
จากนั้นผลลัพธ์จะเป็นดังนี้ขึ้นอยู่กับว่าคุณใช้virtual
/ override
หรือnew
เมื่อประกาศคลาสของคุณ
นี่คือรหัสบางส่วนที่จะเข้าใจถึงความแตกต่างในพฤติกรรมของวิธีการเสมือนและไม่ใช่เสมือน:
class A
{
public void foo()
{
Console.WriteLine("A::foo()");
}
public virtual void bar()
{
Console.WriteLine("A::bar()");
}
}
class B : A
{
public new void foo()
{
Console.WriteLine("B::foo()");
}
public override void bar()
{
Console.WriteLine("B::bar()");
}
}
class Program
{
static int Main(string[] args)
{
B b = new B();
A a = b;
a.foo(); // Prints A::foo
b.foo(); // Prints B::foo
a.bar(); // Prints B::bar
b.bar(); // Prints B::bar
return 0;
}
}
new
"ซ่อน" เมธอดพื้นฐานเมื่อไม่ใช้การแทนที่ดูเหมือนจะทำแบบเดียวกัน?
virtual
และคอมไพเลอร์จะบ่นถ้าเห็นชื่อฟังก์ชันเดียวกันในคลาส "สายเลือด" ที่ไม่มีvirtual
ลายเซ็น
new
คำหลักที่จะสร้างเป็นสมาชิกใหม่ที่สมบูรณ์เท่านั้นที่อยู่ในประเภทที่เฉพาะเจาะจงว่า
ตัวอย่างเช่น
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
วิธีนี้มีอยู่ทั้งสองประเภท เมื่อคุณใช้การไตร่ตรองและรับสมาชิกประเภทBar
คุณจะพบ 2 วิธีที่เรียกDoSomething()
ว่ามีลักษณะเหมือนกันทุกประการ โดยใช้new
คุณมีประสิทธิภาพซ่อนการปฏิบัติในระดับฐานเพื่อที่ว่าเมื่อเรียนมาจากBar
(ในตัวอย่างของฉัน) โทรวิธีการที่จะbase.DoSomething()
ไปและไม่ได้Bar
Foo
virtual / overrideบอกคอมไพเลอร์ว่าทั้งสองวิธีมีความสัมพันธ์กันและในบางกรณีเมื่อคุณคิดว่าคุณกำลังเรียกใช้เมธอดแรก (เสมือน) วิธีนี้ถูกต้องจริงที่จะเรียกวิธีที่สอง (แทนที่) แทน นี่คือรากฐานของความแตกต่าง
(new SubClass() as BaseClass).VirtualFoo()
จะเรียกเมธอด VirtualFoo () overriden ของ SubClass
ใหม่บอกคอมไพเลอร์ว่าคุณกำลังเพิ่มเมธอดไปยังคลาสที่ได้รับซึ่งมีชื่อเดียวกันกับเมธอดในคลาสพื้นฐาน แต่ไม่มีความสัมพันธ์กัน
(new SubClass() as BaseClass).NewBar()
จะเรียกเมธอด NewBar () ของ BaseClass โดยที่:
(new SubClass()).NewBar()
จะเรียกเมธอด NewBar () ของ SubClass
นอกเหนือจากรายละเอียดทางเทคนิคแล้วฉันคิดว่าการใช้ระบบ virtual / override สื่อสารข้อมูลเชิงความหมายจำนวนมากในการออกแบบ เมื่อคุณประกาศเมธอดเสมือนคุณระบุว่าคุณคาดหวังว่าการใช้คลาสอาจต้องการให้มีการใช้งานของตนเองที่ไม่ใช่ค่าเริ่มต้น การละเว้นสิ่งนี้ในคลาสฐานจะประกาศความคาดหวังว่าเมธอดดีฟอลต์ควรเพียงพอสำหรับคลาสที่นำไปใช้ทั้งหมด ในทำนองเดียวกันเราสามารถใช้การประกาศนามธรรมเพื่อบังคับให้ใช้คลาสเพื่อให้การใช้งานของพวกเขาเอง อีกครั้งฉันคิดว่านี่สื่อสารมากเกี่ยวกับวิธีโปรแกรมเมอร์คาดหวังว่ารหัสจะใช้ ถ้าฉันเขียนทั้งฐานและการใช้คลาสและพบว่าตัวเองใช้ใหม่ฉันจะคิดใหม่อย่างจริงจังถึงการตัดสินใจที่จะไม่ทำวิธีการเสมือนจริงในผู้ปกครองและประกาศเจตนาของฉันโดยเฉพาะ
ความแตกต่างระหว่างคีย์เวิร์ดการแทนที่และคีย์เวิร์ดใหม่คือวิธีแรกคือการแทนที่และเมธอดการซ่อนภายหลัง
ตรวจสอบลิงค์ folllowing สำหรับข้อมูลเพิ่มเติม ...
new
คำสำคัญสำหรับการซ่อน - หมายถึงคุณซ่อนวิธีการของคุณไว้ตอนรันไทม์ การส่งออกจะขึ้นอยู่กับวิธีการเรียนพื้นฐานoverride
สำหรับการเอาชนะ - หมายถึงคุณกำลังเรียกใช้วิธีคลาสที่ได้รับโดยอ้างอิงคลาสพื้นฐาน ผลลัพธ์จะขึ้นอยู่กับวิธีการเรียนที่ได้รับคำอธิบายเวอร์ชันของฉันมาจากการใช้คุณสมบัติเพื่อช่วยให้เข้าใจความแตกต่าง
override
ง่ายพอใช่ไหม ประเภทพื้นฐานจะแทนที่ของผู้ปกครอง
new
อาจเป็นความเข้าใจผิด (สำหรับฉันมัน) ด้วยคุณสมบัติทำให้เข้าใจได้ง่ายขึ้น:
public class Foo
{
public bool GetSomething => false;
}
public class Bar : Foo
{
public new bool GetSomething => true;
}
public static void Main(string[] args)
{
Foo foo = new Bar();
Console.WriteLine(foo.GetSomething);
Bar bar = new Bar();
Console.WriteLine(bar.GetSomething);
}
การใช้ดีบักเกอร์คุณสามารถสังเกตเห็นว่าFoo foo
มี2 GetSomething
คุณสมบัติเนื่องจากมันมีคุณสมบัติ 2 เวอร์ชันคือFoo
's และBar
' s และเพื่อให้ทราบว่าจะใช้อันไหน c # "เลือก" คุณสมบัติสำหรับชนิดปัจจุบัน
หากคุณต้องการใช้เวอร์ชันของบาร์คุณจะต้องใช้แทนหรือใช้Foo foo
แทน
Bar bar
มีเพียง1ในขณะที่มันต้องการอย่างสมบูรณ์ใหม่GetSomething
พฤติกรรม
ไม่ทำเครื่องหมายวิธีด้วยวิธีใดหมายถึง: ผูกวิธีนี้โดยใช้ชนิดคอมไพล์ของวัตถุไม่ใช่ประเภทรันไทม์ (การรวมแบบสแตติก)
การทำเครื่องหมายเมธอดด้วยvirtual
วิธีการ: ผูกเมธอดนี้โดยใช้ชนิดรันไทม์ของออบเจ็กต์ไม่ใช่ประเภทเวลาคอมไพล์ (การเชื่อมแบบไดนามิก)
การทำเครื่องหมายvirtual
เมธอดคลาสพื้นฐานด้วยoverride
ในคลาสที่ได้รับหมายถึง: นี่เป็นวิธีการที่ถูกผูกไว้โดยใช้ชนิดรันไทม์ของวัตถุ (การรวมแบบไดนามิก)
การทำเครื่องหมายvirtual
เมธอดคลาสพื้นฐานด้วยnew
ในคลาสที่ได้รับหมายถึง: นี่เป็นวิธีการใหม่ที่ไม่มีความสัมพันธ์กับวิธีที่มีชื่อเดียวกันในคลาสฐานและควรถูกผูกไว้โดยใช้ชนิดเวลารวบรวมของวัตถุ (การรวมแบบสแตติก)
การไม่ทำเครื่องหมายvirtual
วิธีคลาสพื้นฐานในคลาสที่ได้รับหมายถึง: วิธีนี้ถูกทำเครื่องหมายเป็นnew
(การรวมแบบคงที่)
การทำเครื่องหมายเมธอดabstract
หมายถึง: วิธีนี้เป็นเสมือน แต่ฉันจะไม่ประกาศเนื้อความสำหรับมันและคลาสของมันก็เป็นนามธรรม (การเชื่อมโยงแบบไดนามิก)
new
สร้างสมาชิกใหม่ที่มีชื่อเดียวกันและทำให้สมาชิกเดิมถูกซ่อนในขณะที่override
ขยายการใช้งานสำหรับสมาชิกที่สืบทอด"