C # - การใช้คำหลักเสมือน + แทนที่กับใหม่


204

อะไรคือความแตกต่างระหว่างการประกาศวิธีการในประเภทฐาน " virtual" แล้วแทนที่มันในประเภทลูกโดยใช้overrideคำหลัก "" ซึ่งตรงข้ามกับการใช้newคำหลัก "" เมื่อประกาศวิธีการจับคู่ในประเภทลูก


3
MSDNพูดว่า "การใช้newสร้างสมาชิกใหม่ที่มีชื่อเดียวกันและทำให้สมาชิกเดิมถูกซ่อนในขณะที่overrideขยายการใช้งานสำหรับสมาชิกที่สืบทอด"
AminM


คำตอบ:


181

คำหลัก "ใหม่" ไม่ได้แทนที่มันหมายถึงวิธีการใหม่ที่ไม่เกี่ยวข้องกับวิธีการเรียนพื้นฐาน

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" คือเมื่อเมธอดไม่เกี่ยวข้องในทางใดทางหนึ่งกับเวอร์ชันคลาสพื้นฐาน


คุณควรแก้ไขรหัสของคุณฉันได้ทำวิธีการแบบคงที่ (ซึ่งถูกต้องสำหรับการใช้คำหลัก "ใหม่") แต่ฉันคิดว่ามันชัดเจนกว่าที่จะใช้วิธีการแบบอินสแตนซ์
โจเซฟไดเกิล

1
ขอบคุณฉันพลาดส่วน "คงที่" ควรให้ความสำคัญกับอนาคตมากขึ้น
อัลเบอซินใน

1
โปรดทราบว่าบรรทัด Foo test = new Bar () มีความสำคัญที่นี่คำหลักใหม่ / การแทนที่สำหรับ metods จะกำหนดว่าจะเรียก metod ใดเมื่อคุณใส่ Bar ลงในตัวแปร Foo
โทมัส N

... ดังนั้นมันเหมือนกันกับที่ไม่ได้virtualอยู่ในฐานและที่overrideได้มา? ทำไมมันมีอยู่? รหัสจะยังคงทำงานแม้ไม่มีnew- ดังนั้นมันเป็นเพียงแค่การอ่านอย่างหมดจด?
Don Cheadle

คำตอบของคุณที่รักค่อนข้างคลุมเครือ ใหม่และการแทนที่เสมือนทำสิ่งเดียวกันสวยความแตกต่างเพียงอย่างเดียวคือ HIDES ใหม่เป็นวิธีการในระดับผู้ปกครองและแทนที่ .. ดีแทนที่มัน แน่นอนว่ามันพิมพ์ผิดเนื่องจากวัตถุทดสอบของคุณเป็นประเภท Foo ถ้าเป็นประเภท Bar ก็จะพิมพ์จริง ตัวอย่างที่ค่อนข้างยุ่งยาก
MrSilent

228

ฉันมักพบสิ่งต่าง ๆ เช่นนี้เข้าใจได้ง่ายขึ้นด้วยรูปภาพ

อีกครั้งรับรหัสของ 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เมื่อประกาศคลาสของคุณ

รูปภาพคำอธิบาย Virtual / Override


3
ขอบคุณ .... แต่คุณช่วยอธิบายภาพเกี่ยวกับการคัดเลือกนักแสดงที่คุณพูดหน่อยได้ไหม?
odiseh

โอ๊ะหากลืมที่จะเพิ่มสองสามบรรทัดนี้ไปก่อนหน้า หมายเหตุ: คุณหมายถึง virtual / overriding และ non-vitual / new ถูกใช้สำหรับแนวคิด polymorphysm และเมื่อคุณประกาศตัวแปร (ไม่ได้ใช้การคัดเลือก) พวกเขาไม่ได้หมายความว่าอย่างไร ขอบคุณอีกครั้ง.
odiseh

คำตอบนี้เป็นสิ่งที่ฉันกำลังมองหา ปัญหาเดียวที่ฉันมีเป็น Flickr ว่าภาพจะถูกบล็อกในสถานที่ทำงานของฉันเพื่อให้ฉันได้เข้าถึงได้ผ่านทางโทรศัพท์ของฉัน ...
mezoid

7
ความพยายามอย่างแท้จริงในการตอบคำถาม
iMatoria

ฉันจะลงคะแนนถ้าคุณสามารถแก้ไขภาพ? มันถูกบล็อคไว้ข้างหลังไฟร์วอลล์ไฟร์วอลล์ ...
เจเรมี ธ อมป์สัน

43

นี่คือรหัสบางส่วนที่จะเข้าใจถึงความแตกต่างในพฤติกรรมของวิธีการเสมือนและไม่ใช่เสมือน:

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"ซ่อน" เมธอดพื้นฐานเมื่อไม่ใช้การแทนที่ดูเหมือนจะทำแบบเดียวกัน?
Don Cheadle

1
ฉันไม่คิดว่ามันถูกสร้างขึ้นเพื่อป้องกันชั้นฐานจากการถูก overriden ฉันคิดว่ามันถูกสร้างขึ้นเพื่อหลีกเลี่ยงการปะทะกันของชื่อเนื่องจากคุณไม่สามารถแทนที่วิธีที่ไม่ใช่virtualและคอมไพเลอร์จะบ่นถ้าเห็นชื่อฟังก์ชันเดียวกันในคลาส "สายเลือด" ที่ไม่มีvirtualลายเซ็น
mr5

19

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()ไปและไม่ได้BarFoo


9

virtual / overrideบอกคอมไพเลอร์ว่าทั้งสองวิธีมีความสัมพันธ์กันและในบางกรณีเมื่อคุณคิดว่าคุณกำลังเรียกใช้เมธอดแรก (เสมือน) วิธีนี้ถูกต้องจริงที่จะเรียกวิธีที่สอง (แทนที่) แทน นี่คือรากฐานของความแตกต่าง

(new SubClass() as BaseClass).VirtualFoo()

จะเรียกเมธอด VirtualFoo () overriden ของ SubClass

ใหม่บอกคอมไพเลอร์ว่าคุณกำลังเพิ่มเมธอดไปยังคลาสที่ได้รับซึ่งมีชื่อเดียวกันกับเมธอดในคลาสพื้นฐาน แต่ไม่มีความสัมพันธ์กัน

(new SubClass() as BaseClass).NewBar()

จะเรียกเมธอด NewBar () ของ BaseClass โดยที่:

(new SubClass()).NewBar()

จะเรียกเมธอด NewBar () ของ SubClass


ชอบประโยคนี้ "บอกคอมไพเลอร์"
Mina Gabriel

"รากฐานของความแตกต่าง" ดีงามอีกบอก :)
เจเรมี ธ อมป์สัน

8

นอกเหนือจากรายละเอียดทางเทคนิคแล้วฉันคิดว่าการใช้ระบบ virtual / override สื่อสารข้อมูลเชิงความหมายจำนวนมากในการออกแบบ เมื่อคุณประกาศเมธอดเสมือนคุณระบุว่าคุณคาดหวังว่าการใช้คลาสอาจต้องการให้มีการใช้งานของตนเองที่ไม่ใช่ค่าเริ่มต้น การละเว้นสิ่งนี้ในคลาสฐานจะประกาศความคาดหวังว่าเมธอดดีฟอลต์ควรเพียงพอสำหรับคลาสที่นำไปใช้ทั้งหมด ในทำนองเดียวกันเราสามารถใช้การประกาศนามธรรมเพื่อบังคับให้ใช้คลาสเพื่อให้การใช้งานของพวกเขาเอง อีกครั้งฉันคิดว่านี่สื่อสารมากเกี่ยวกับวิธีโปรแกรมเมอร์คาดหวังว่ารหัสจะใช้ ถ้าฉันเขียนทั้งฐานและการใช้คลาสและพบว่าตัวเองใช้ใหม่ฉันจะคิดใหม่อย่างจริงจังถึงการตัดสินใจที่จะไม่ทำวิธีการเสมือนจริงในผู้ปกครองและประกาศเจตนาของฉันโดยเฉพาะ


คำอธิบายทางเทคนิคของการแทนที่ vs ใหม่เป็นเสียง แต่คำตอบนี้ดูเหมือนจะช่วยได้มากที่สุดสำหรับการแนะนำ devs ที่จะใช้
Sully

4

ความแตกต่างระหว่างคีย์เวิร์ดการแทนที่และคีย์เวิร์ดใหม่คือวิธีแรกคือการแทนที่และเมธอดการซ่อนภายหลัง

ตรวจสอบลิงค์ folllowing สำหรับข้อมูลเพิ่มเติม ...

MSDN และ อื่น ๆ


3
  • newคำสำคัญสำหรับการซ่อน - หมายถึงคุณซ่อนวิธีการของคุณไว้ตอนรันไทม์ การส่งออกจะขึ้นอยู่กับวิธีการเรียนพื้นฐาน
  • overrideสำหรับการเอาชนะ - หมายถึงคุณกำลังเรียกใช้วิธีคลาสที่ได้รับโดยอ้างอิงคลาสพื้นฐาน ผลลัพธ์จะขึ้นอยู่กับวิธีการเรียนที่ได้รับ

1

คำอธิบายเวอร์ชันของฉันมาจากการใช้คุณสมบัติเพื่อช่วยให้เข้าใจความแตกต่าง

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พฤติกรรม


0

ไม่ทำเครื่องหมายวิธีด้วยวิธีใดหมายถึง: ผูกวิธีนี้โดยใช้ชนิดคอมไพล์ของวัตถุไม่ใช่ประเภทรันไทม์ (การรวมแบบสแตติก)

การทำเครื่องหมายเมธอดด้วยvirtualวิธีการ: ผูกเมธอดนี้โดยใช้ชนิดรันไทม์ของออบเจ็กต์ไม่ใช่ประเภทเวลาคอมไพล์ (การเชื่อมแบบไดนามิก)

การทำเครื่องหมายvirtualเมธอดคลาสพื้นฐานด้วยoverrideในคลาสที่ได้รับหมายถึง: นี่เป็นวิธีการที่ถูกผูกไว้โดยใช้ชนิดรันไทม์ของวัตถุ (การรวมแบบไดนามิก)

การทำเครื่องหมายvirtualเมธอดคลาสพื้นฐานด้วยnewในคลาสที่ได้รับหมายถึง: นี่เป็นวิธีการใหม่ที่ไม่มีความสัมพันธ์กับวิธีที่มีชื่อเดียวกันในคลาสฐานและควรถูกผูกไว้โดยใช้ชนิดเวลารวบรวมของวัตถุ (การรวมแบบสแตติก)

การไม่ทำเครื่องหมายvirtualวิธีคลาสพื้นฐานในคลาสที่ได้รับหมายถึง: วิธีนี้ถูกทำเครื่องหมายเป็นnew(การรวมแบบคงที่)

การทำเครื่องหมายเมธอดabstractหมายถึง: วิธีนี้เป็นเสมือน แต่ฉันจะไม่ประกาศเนื้อความสำหรับมันและคลาสของมันก็เป็นนามธรรม (การเชื่อมโยงแบบไดนามิก)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.