Anahtar kelime kullanımı sanal + geçersiz kılma vs yeni


204

" virtual" Temel türünde bir yöntem bildirmek ve sonra alt türdeki eşleştirme yöntemini bildirirken override" new" anahtar sözcüğünü kullanmak yerine " " anahtar sözcüğünü kullanarak alt öğe türünde geçersiz kılmak arasındaki farklar nelerdir ?


3
MSDN , " newoverride
Use


Yanıtlar:


181

"New" anahtar sözcüğü geçersiz kılmaz, temel sınıf yöntemiyle ilgisi olmayan yeni bir yöntemi belirtir.

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

Geçersiz yazdıysanız, true yazdırılır.

(Temel kod Joseph Daigle'den alınmıştır)

Yani, gerçek bir polimorfizm yapıyorsanız, DAİMA GEÇERSİZ OLMALISINIZ . "New" kullanmanız gereken tek yer, yöntemin temel sınıf sürümüyle hiçbir şekilde ilişkili olmadığı durumdur.


Kodunuzu gözden geçirmelisiniz, yöntemleri statik yapmıştım ("yeni" anahtar kelimesini kullanmak için geçerlidir). Ancak, örnek yöntemlerini kullanmanın daha açık olduğuna karar verdim.
Joseph Daigle

1
Teşekkür ederim, "statik" bölümünü kaçırdım. Gelecekte daha fazla dikkat etmeli
albertein

1
Burada Foo testi = new Bar () satırının çok önemli olduğunu unutmayın, metodlar için new / override anahtar sözcüğü, Foo değişkenine bir Bar eklediğinizde hangi metodun çağrıldığını belirler.
Thomas N

... yani sadece tam olarak aynı olduğunu değil sahip virtualtabanında ve overridetüretilmiş içinde? Neden var? Kod w / o ile bile çalışmaya devam edecek new- sadece okunabilirlik mi?
Don Cheadle

Cevabınız sevgili efendim oldukça belirsiz. yeni ve sanal geçersiz kılma aynı şeyi yapar, tek fark, yeni üst sınıftaki yöntemi saklar ve geçersiz kılar .. iyi, geçersiz kılar. Elbette yanlış yazdırır, çünkü test nesneniz Foo türündedir, Bar türünde olursa true yazdırır. Yine de oldukça zor bir örnek.
MrSilent

228

Resimlerle her zaman daha kolay anlaşılır şeyler bulurum:

Yine, Joseph Daigle'in kodunu alarak,

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

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

Daha sonra kodu şöyle çağırırsanız:

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

NOT: Önemli olan, nesnemizin aslında bir olmasıdır Bar, ancak onu değişken bir türde saklıyoruzFoo (bu, döküm yapmaya benzer)

Daha sonra sonuç, kullandığınız virtual/ overrideveya newsınıflarınızı bildirirken bağlı olarak aşağıdaki gibi olacaktır .

Sanal / Geçersiz Kılma açıklama resmi


3
Teşekkürler .... ama söylediğin döküm ile ilgili yukarıdaki resim hakkında biraz açıklayabilir misin?
odiseh

Hata! Eğer bu birkaç satırı benim önceki eklersem. comment: Sanal / geçersiz kılma ve vitual olmayan / yeni sadece polimorfizm kavramı için mi kullanılıyor ve basitçe bir değişken (döküm kullanmadan) beyan ettiğinizde bunlar demek değil mi? Tekrar teşekkürler.
odiseh

bu cevap tam da aradığım şeydi. Sahip olduğum tek sorun flickr görüntüleri işyerinde bloke edildi, bu yüzden telefonumla erişmek zorunda kaldım ...
mezoid

7
Soruyu cevaplamak için gerçek çaba.
iMatoria

Görüntüyü düzeltebilir misiniz? Corp güvenlik duvarının arkasında engellendi ...
Jeremy Thompson

43

Sanal ve sanal olmayan yöntemlerin davranışlarındaki farkı anlamak için bazı kodlar:

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

bunun için teşekkür ederim - ama neden newgeçersiz kılmayı kullanmıyorken temel yöntemi "gizlemek" için kullanmak aynı şeyi yapıyor gibi görünüyor?
Don Cheadle

1
Temel sınıfın geçersiz kılınmasını önlemek için yaratıldığını sanmıyorum. Ben olmayan bir yöntemi geçersiz virtualvirtual
kılamıyor

19

newAnahtar kelime aslında sadece o belirli tipine var tamamen yeni bir üye yaratır.

Örneğin

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

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

Yöntem her iki tipte de mevcuttur. Yansımayı kullandığınızda ve türün üyelerini Baraldığınızda, aslında DoSomething()tam olarak aynı görünen 2 yöntem bulacaksınız . Kullanarak newetkili bir şekilde temel sınıfta uygulamayı gizler, böylece sınıflar Bar(benim örneğimde) türetildiğinde yöntem çağrısına base.DoSomething()gider Barve gitmez Foo.


9

sanal / geçersiz kılma derleyiciye iki yöntemin ilişkili olduğunu ve bazı durumlarda ilk (sanal) yöntemi çağırdığınızı düşündüğünüzde bunun yerine ikinci (geçersiz kılınmış) yöntemi çağırmanın doğru olduğunu söyler. Bu polimorfizmin temelidir.

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

Alt Sınıf'ın geçersiz kılınmış VirtualFoo () yöntemini çağırır.

new derleyiciye, türetilmiş bir sınıfa temel sınıftaki bir yöntemle aynı ada sahip bir yöntem eklediğinizi söyler, ancak birbirleriyle hiçbir ilişkisi yoktur.

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

BaseClass'ın NewBar () yöntemini çağırır, oysa:

(new SubClass()).NewBar()

Alt Sınıf'ın NewBar () yöntemini çağırır.


gerçekten bu cümleyi "derleyiciye söyler" gibi
Mina Gabriel

"polimorfizmin temeli" başka bir şık söz :)
Jeremy Thompson

8

Sadece teknik detayların ötesinde, sanal / geçersiz kılmanın tasarım hakkında birçok anlamsal bilgi aktardığını düşünüyorum. Sanal bir yöntem bildirdiğinizde, uygulama sınıflarının kendi varsayılan olmayan uygulamaları sağlamak isteyebileceğini beklersiniz. Bunu bir temel sınıfta atlamak, aynı şekilde, varsayılan yöntemin tüm uygulayıcı sınıflar için yeterli olması beklentisini açıklar. Benzer şekilde, uygulama sınıflarını kendi uygulamalarını sağlamaya zorlamak için soyut bildirimler kullanılabilir. Yine, bu programcı kullanılacak kodu nasıl beklediğini hakkında çok şey ifade düşünüyorum. Hem üs hem de uygulama sınıfları yazıyor ve kendimi yeni kullanarak bulsaydım, yöntemi ebeveynte sanal hale getirmeme ve özellikle niyetimi beyan etmeme kararını ciddi olarak yeniden düşünürdüm.


Yeni ve geçersiz kılmanın teknik açıklamaları sağlamdır, ancak bu cevap, kullanılacak geliştiricilere rehberlik etmek için en çok yardımcı gibi görünmektedir.
Sully

4

Override anahtar sözcüğü ve yeni anahtar kelime arasındaki fark, eski yöntem geçersiz kılma ve daha sonra yöntem gizleme yapar.

Daha fazla bilgi için aşağıdaki linklere göz atın ...

MSDN ve Diğer


3
  • newanahtar kelime Gizleme içindir. - yönteminizi çalışma zamanında gizlediğiniz anlamına gelir. Çıktı, temel sınıf yöntemine dayalı olacaktır.
  • overridegeçersiz kılmak için. - türetilmiş sınıf yönteminizi temel sınıf referansıyla çağırdığınız anlamına gelir. Çıktı türetilmiş sınıf yöntemine dayalı olacaktır.

1

Açıklama sürümüm , farklılıkları anlamaya yardımcı olması için özellikleri kullanmaktan geliyor .

overrideyeterince basit, değil mi? Altta yatan tür , üst öğeyi geçersiz kılar .

newbelki de yanıltıcıdır (benim için öyleydi). Özelliklerle anlaşılması daha kolaydır:

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

Bir hata ayıklayıcı kullanarak Foo foo, 2 GetSomething özelliğe sahip olduğunu fark edebilirsiniz , çünkü aslında Foo's ve Bar' özelliklerinin 2 sürümüne sahiptir ve hangisini kullanacağını bilmek için, c # geçerli tür için özelliği "seçer".

Çubuğun sürümünü kullanmak isterseniz, Foo foobunun yerine geçersiz kılmayı veya kullanmayı kullanırdınız.

Bar bartamamen yeni bir davranış istediği için sadece 1 vardır .GetSomething


0

Bir yöntemi herhangi bir şeyle işaretlememek şu anlama gelir: Bu yöntemi, çalışma zamanı türünü değil, nesnenin derleme türünü kullanarak bağlayın (statik bağlama).

Bir yöntemi virtualaraçlarla işaretleme : Zaman yöntemini (dinamik bağlama) değil, nesnenin çalışma zamanı türünü kullanarak bu yöntemi bağlayın.

Temel sınıf virtualyöntemini overridetüretilmiş sınıfta işaretlemek şu anlama gelir: Bu, nesnenin çalışma zamanı türü (dinamik bağlama) kullanılarak bağlanacak yöntemdir.

Temel sınıf virtualyönteminin newtüretilmiş sınıfta işaretlenmesi şu anlama gelir: Bu, temel sınıfta aynı ada sahip olanla hiçbir ilişkisi olmayan yeni bir yöntemdir ve nesnenin derleme zamanı türü (statik bağlanma) kullanılarak bağlanması gerekir.

Temel sınıf virtualyönteminin türetilmiş sınıfta işaretlenmemesi şu anlama gelir: Bu yöntem new(statik bağlama) olarak işaretlenir .

Bir yöntemin işaretlenmesi şu abstractanlama gelir: Bu yöntem sanaldır, ancak bunun için bir gövde beyan etmeyeceğim ve sınıfı da soyuttur (dinamik bağlama).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.