C # - Penggunaan kata kunci virtual + override vs baru

204

Apa perbedaan antara mendeklarasikan metode dalam tipe dasar " virtual" dan kemudian menimpanya dalam tipe anak menggunakan " override" kata kunci dibandingkan dengan hanya menggunakan newkata kunci " " ketika mendeklarasikan metode pencocokan dalam tipe anak?

i3ensays
sumber
3
MSDN mengatakan "Menggunakan newmembuat anggota baru dengan nama yang sama dan menyebabkan anggota asli menjadi tersembunyi, sementara overridememperluas implementasi untuk anggota yang diwariskan"
AminM

Jawaban:

181

Kata kunci "baru" tidak menggantikan, itu menandakan metode baru yang tidak ada hubungannya dengan metode kelas dasar.

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 ());
    }
}

Ini mencetak false, jika Anda menimpanya akan dicetak benar.

(Kode dasar diambil dari Joseph Daigle)

Jadi, jika Anda melakukan polimorfisme nyata, Anda HARUS SELALU BERLEBIHAN . Satu-satunya tempat di mana Anda perlu menggunakan "baru" adalah ketika metode ini tidak terkait dengan cara apa pun dengan versi kelas dasar.

albertein
sumber
Anda harus merevisi kode Anda, saya telah membuat metode statis (yang berlaku untuk menggunakan kata kunci "baru"). Tapi saya memutuskan lebih jelas menggunakan metode instan.
Joseph Daigle
1
Terima kasih, saya melewatkan bagian "statis". Harus lebih memperhatikan masa depan
albertein
1
Perhatikan bahwa tes baris Foo = bilah baru () sangat penting di sini, kata kunci baru / timpa untuk metod menentukan metod mana yang dipanggil saat Anda memasukkan Bilah ke dalam variabel Foo.
Thomas N
... jadi sama persis seperti tidak memiliki virtualdi pangkalan dan overridediturunkan? Kenapa itu ada? Kode masih akan berjalan bahkan tanpa new- jadi apakah ini murni keterbacaan saja?
Don Cheadle
Jawaban Anda, Tuan, cukup jelas. baru dan virtual-override melakukan hal yang sama, satu-satunya perbedaan adalah bahwa menyembunyikan metode baru di kelas induk dan menimpa .. baik, menimpanya. Tentu saja itu mencetak false karena objek pengujian Anda adalah tipe Foo, jika itu akan menjadi tipe Bar, itu akan mencetak benar. Contoh yang cukup rumit.
MrSilent
228

Saya selalu menemukan hal-hal seperti ini lebih mudah dipahami dengan gambar:

Sekali lagi, mengambil kode joseph daigle,

public class Foo
{
     public /*virtual*/ bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public /*override or new*/ bool DoSomething() { return true; }
}

Jika Anda memanggil kode seperti ini:

Foo a = new Bar();
a.DoSomething();

CATATAN: Yang penting adalah bahwa objek kita sebenarnya a Bar, tetapi kita menyimpannya dalam variabel tipeFoo (ini mirip dengan menuangnya)

Maka hasilnya adalah sebagai berikut, tergantung pada apakah Anda menggunakan virtual/ overrideatau newketika mendeklarasikan kelas Anda.

Gambar penjelasan Virtual / Override

Orion Edwards
sumber
3
Terima kasih .... tetapi bisakah Anda menjelaskan sedikit tentang gambar di atas sehubungan dengan casting yang Anda katakan?
odiseh
Ups Jika lupa menambahkan beberapa baris ini ke prev saya. komentar: maksud Anda virtual / overriding dan non-vitual / baru digunakan hanya untuk konsep polimorfisme dan ketika Anda hanya mendeklarasikan variabel (tidak menggunakan casting) itu tidak berarti? Terima kasih lagi.
odiseh
jawaban ini persis apa yang saya cari. Satu-satunya masalah yang saya miliki adalah bahwa gambar flickr diblokir di tempat kerja saya sehingga saya harus mengaksesnya melalui telepon saya ...
mezoid
7
Upaya nyata untuk menjawab pertanyaan itu.
iMatoria
Saya akan menyesal jika Anda dapat memperbaiki gambar? Diblokir di belakang corp firewall ...
Jeremy Thompson
43

Berikut ini beberapa kode untuk memahami perbedaan dalam perilaku metode virtual dan non-virtual:

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;
    }
}
Franci Penov
sumber
terima kasih untuk ini - tetapi mengapa menggunakan newuntuk "menyembunyikan" metode dasar, ketika tidak menggunakan override tampaknya melakukan hal yang sama?
Don Cheadle
1
Saya tidak berpikir itu dibuat untuk mencegah kelas dasar ditimpa. Saya pikir itu dibuat untuk menghindari bentrok nama karena Anda tidak dapat menimpa metode yang tidak virtualdan kompiler akan mengeluh jika melihat nama fungsi yang sama pada kelas "garis keturunan" tanpa virtualtanda tangan
mr5
19

Kata newkunci sebenarnya membuat anggota yang sama sekali baru yang hanya ada pada jenis tertentu.

Misalnya

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

Metode ini ada pada kedua jenis. Ketika Anda menggunakan refleksi dan mendapatkan anggota tipe Bar, Anda akan benar-benar menemukan 2 metode DoSomething()yang terlihat persis sama. Dengan menggunakan newAnda secara efektif menyembunyikan implementasi di kelas dasar, sehingga ketika kelas berasal dari Bar(dalam contoh saya) panggilan metode untuk base.DoSomething()pergi ke Bardan tidak Foo.

Joseph Daigle
sumber
9

virtual / override memberitahu kompiler bahwa kedua metode terkait dan bahwa dalam beberapa keadaan ketika Anda akan berpikir Anda memanggil metode pertama (virtual) itu benar untuk memanggil metode kedua (override) sebagai gantinya. Ini adalah dasar dari polimorfisme.

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

Akan memanggil metode VirtualFoo () utama SubClass.

baru memberitahu kompiler bahwa Anda menambahkan metode ke kelas turunan dengan nama yang sama dengan metode di kelas dasar, tetapi mereka tidak memiliki hubungan satu sama lain.

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

Akan memanggil metode NewBar () BaseClass, sedangkan:

(new SubClass()).NewBar()

Akan memanggil metode NewCar () SubClass.

Baji
sumber
sangat suka kalimat ini "menceritakan kompiler"
Mina Gabriel
"fondasi polimorfisme" adalah pepatah lain yang berkelas :)
Jeremy Thompson
8

Selain detail teknis, saya pikir menggunakan virtual / override mengkomunikasikan banyak informasi semantik pada desain. Ketika Anda mendeklarasikan metode virtual, Anda mengindikasikan bahwa Anda berharap bahwa kelas implementasi mungkin ingin menyediakan implementasi mereka sendiri, non-default. Menghilangkan ini dalam kelas dasar, juga, menyatakan harapan bahwa metode default harus mencukupi untuk semua kelas implementasi. Demikian pula, seseorang dapat menggunakan deklarasi abstrak untuk memaksa kelas implementasi untuk menyediakan implementasi mereka sendiri. Sekali lagi, saya pikir ini banyak berkomunikasi tentang bagaimana programmer mengharapkan kode yang akan digunakan. Jika saya menulis basis dan kelas implementasi dan mendapati diri saya menggunakan yang baru, saya serius akan memikirkan kembali keputusan untuk tidak membuat metode virtual pada orang tua dan menyatakan maksud saya secara khusus.

tvanfosson
sumber
Penjelasan teknis tentang penggantian baru vs yang masuk akal, tetapi jawaban ini tampaknya paling membantu untuk membimbing para dev yang akan digunakan.
Sully
4

Perbedaan antara kata kunci override dan kata kunci baru adalah bahwa yang pertama melakukan overriding metode dan kemudian yang bersembunyi metode.

Lihat tautan berikut untuk informasi lebih lanjut ...

MSDN dan Lainnya

Nescio
sumber
3
  • newkata kunci untuk Menyembunyikan. - Berarti Anda menyembunyikan metode Anda saat runtime. Output akan didasarkan pada metode kelas dasar.
  • overrideuntuk mengganti. - berarti Anda menggunakan metode kelas turunan Anda dengan referensi kelas dasar. Output akan didasarkan pada metode kelas turunan.
Chetan
sumber
1

Versi penjelasan saya berasal dari penggunaan properti untuk membantu memahami perbedaan.

overridecukup sederhana kan? Jenis yang mendasari menimpa orang tua.

newmungkin menyesatkan (bagi saya itu). Dengan properti lebih mudah dipahami:

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);
}

Menggunakan debugger Anda dapat melihat bahwa Foo fooada 2 GetSomething properti, karena sebenarnya memiliki 2 versi properti, FoodanBar ', dan untuk mengetahui mana yang akan digunakan, c # "mengambil" properti untuk jenis saat ini.

Jika Anda ingin menggunakan versi Bar, Anda akan menggunakan penggantian atau gunakan Foo foosebagai gantinya.

Bar bar hanya memiliki 1 , karena ingin perilaku yang sama sekali baru untuk GetSomething.

Dror Weiss
sumber
0

Tidak menandai metode dengan apa pun berarti: Bind metode ini menggunakan tipe kompilasi objek, bukan tipe runtime (pengikatan statis).

Menandai metode dengan virtual cara: Bind metode ini menggunakan tipe runtime objek, bukan tipe waktu kompilasi (pengikatan dinamis).

Menandai virtualmetode kelas dasar dengan overridekelas turunan berarti: Ini adalah metode yang akan diikat menggunakan tipe runtime objek (pengikatan dinamis).

Menandai virtualmetode kelas dasar dengan newkelas turunan berarti: Ini adalah metode baru, yang tidak memiliki hubungan dengan yang memiliki nama yang sama di kelas dasar dan harus diikat menggunakan jenis waktu kompilasi objek (pengikatan statis).

Tidak menandai virtualmetode kelas dasar dalam kelas turunan berarti: Metode ini ditandai sebagai new(pengikatan statis).

Menandai metode abstractberarti: Metode ini virtual, tetapi saya tidak akan mendeklarasikan sebuah tubuh untuk itu dan kelasnya juga abstrak (pengikatan dinamis).

Emre Tapcı
sumber