C # 'ta gölgeleme ve geçersiz kılma arasındaki fark nedir?


102

C # 'da gölgeleme ile bir yöntemi geçersiz kılma arasındaki fark nedir ?

Yanıtlar:


154

Peki miras ...

bu sınıflara sahip olduğunuzu varsayalım:

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
}

sonra bunu aradığınızda:

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

Bir temel sınıfınız olduğunu ve devralınan sınıflar yerine tüm kodunuzda temel sınıfı kullandığınızı ve gölge kullandığınızı varsayalım, nesnenin gerçek türünün miras ağacını izlemek yerine temel sınıfın döndürdüğü değerleri döndürür.

Kodu burada çalıştırın

Umarım mantıklıyım :)


17
Geçersiz kılma, polimorfizm sağlar, gölgeleme, hiyerarşinin bu düzeyinde farklı bir uygulama sağlar, ancak polimorf olarak değil.
David Rodríguez - dribeas

@dribeas, Bu sonuca varmak için polimorfizmin hangi tanımını kullanırsınız?
AnthonyWJones

9
@AnthonyWJones, Polimorfizm, bir (türetilmiş) türün, gerçek uygulamanın (davranış) gerçek belirli (türetilmiş) tür olduğu farklı (temel) bir tür olarak kullanılabilme yeteneğidir. Geçersiz kılarsanız, türetilmiş yöntem tabana referansla çağrılacaktır, ancak bunun doğru olmadığını gölgelerseniz
David Rodríguez -

2
Bana öyle geliyor ki, örnek kodunuzda bir hata var. Döküm ((A) clB) .Foo () olmalı, değil mi?
trendl

1
Hayır, bar sanal olduğu için B Bar
Stormenet

32

Gölgelendirme, aslında C # 'ta saklanma olarak adlandırdığımız şeyin VB ifadesidir.

Genellikle gizleme ( VB'de gölgeleme) ve geçersiz kılma Stormenet tarafından yanıtlandığı gibi gösterilir .

Bir sanal yöntemin bir alt sınıf tarafından geçersiz kılındığı gösterilir ve bu yönteme yapılan çağrılar, süper sınıf türünde veya süper sınıfın kodunun içinden bile alt sınıftan değiştirme uygulamasını çağırır.

Daha sonra new, alt sınıf üzerinde aynı imzaya sahip bir yöntemi tanımlarken anahtar kelime kullanılarak gizlenmiş somut bir yöntem (sanal veya soyut olarak işaretlenmemiş) gösterilir . Bu durumda yöntem süper sınıf türünde çağrıldığında, orijinal uygulama kullanılır, yeni uygulama yalnızca alt sınıfta kullanılabilir.

Ancak çoğu kez gözden kaçan şey, sanal bir yöntemi gizlemenin de mümkün olmasıdır.

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.

Yukarıdaki örnekte DoStuff somut hale gelir ve geçersiz kılınamaz. Ancak hem virtualve hem de newanahtar kelimelerin birlikte kullanılması da mümkündür .

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.

Tüm yöntemlerin sanal olmasına rağmen, C üzerindeki geçersiz kılma, newB'nin kullanımının A uygulamasını gizlediğinden, A'daki sanal yöntemi etkilemediğini unutmayın .

Düzenleme: Bu cevaba yapılan yorumlarda, yukarıdakilerin tehlikeli olabileceği veya en azından özellikle yararlı olmayabileceği belirtilmiştir. Evet, tehlikeli olabilir ve yararlı olsaydı orada olurdu derdim.

Özellikle erişilebilirlik değiştiricilerini de değiştirirseniz her türlü soruna maruz kalabilirsiniz. Örneğin:-

public class Foo
{
    internal Foo() { }
    protected virtual string Thing() { return "foo"; }
}

public class Bar : Foo
{
 internal new string Thing() { return "bar"; }
}

Dış mirasçısına Bar, Foo'nin Thing () uygulaması erişilebilir ve geçersiz kılınabilir. Tüm yasal ve açıklanabilir .NET türü kurallara göre asla sezgisel değildir.

Bu yanıtı, özgürce kullanılabilecek tekniklerin bir önerisi olarak değil, işlerin nasıl çalıştığına dair bir anlayışı derinleştirmek için gönderdim.


2
Bunu bilmek güzel. Kullanımı tehlikeli olsa da :)
Stormenet

2
Doğru kullanılmadığında tüm aletler tehlikeli olabilir.
AnthonyWJones

1
Ancak, kullanılabilirliği gerçekten şüpheli görünüyor! Bunu kullanan herhangi bir 'ciddi' açık kaynaklı uygulama var mı?
Jox

4
Kullanılabilirlik? Yararlılık mı demek istiyorsun? Sınırda olan bazı şeyler, ihtiyacınız olana kadar işe yaramaz görünebilir.
AnthonyWJones

Görünüşe göre Gölgeleme SADECE sanal ve yeni oyunlar oynandığında resme geliyor. @ Stormenet, sanal olmadığı sürece sınıfın kendi yöntemini çağırması normal olduğundan, yalnızca geçersiz kılma olayını açıklıyor.
Sumit Kapadia


5

Gölgeleme bir VB.NET konseptidir. C # 'da, Gölgeleme, Gizleme olarak bilinir. Türetilmiş sınıf yöntemini gizler. 'Yeni' anahtar kelimesi kullanılarak gerçekleştirilir.

Override anahtar sözcüğü, türetilmiş sınıfta bir temel sınıf yönteminin ('Sanal' olarak işaretlenen) tamamen yeni bir uygulamasını sağlamak için kullanılır.


Diyorsun ki. Türetilmiş sınıf yöntemini gizler, bunun yerine temel sınıf yöntemini kullanır. ?
shaijut

0

Temel olarak aşağıdaki gibi bir şeyiniz varsa,

Class A
{
}

Class B:A
{
}

A a = new B();

'A' nesnesinde çağırdığınız herhangi bir yöntem, 'a' türünde yapılacaktır (Burada tür 'A'dır) Ancak, aynı yöntemi B Sınıfında zaten A Sınıfında mevcut olan aynı yöntemi uygularsanız, derleyici "Yeni" bir anahtar kelime kullanmanız için sizi uyarır. "Yeni" kullanırsanız, uyarı kaybolur. Bunun dışında, miras alınan sınıfta "Yeni" kullanmakla kullanmamak arasında bir fark yoktur.

Bazı durumlarda, nesne türünde bir yöntemi çağırmak yerine, o anda belirli örneğin tuttuğu referans sınıfının bir yöntemini çağırmanız gerekebilir. Yukarıdaki durumda, tuttuğu referans 'B'dir, ancak tür' A'dır. Dolayısıyla, yöntem çağrısının 'B'de olmasını istiyorsanız, bunu başarmak için Sanal'ı kullanır ve geçersiz kılarsınız.

Bu yardımcı olur umarım...

Daniel Sandeep.


0

Bir sınıfın içeriğini değiştiremeyeceğiniz bir durum varsa, diyelim A, ancak onun bazı yöntemlerini kullanmak istiyorsanız, aynı adı taşıyan bir yönteme sahipseniz, newanahtar kelime ile kendi yöntem uygulamanızı kullanabilirsiniz .

İşin püf noktası, hem referansın hem de nesnenin aynı türde olması gerektiğini kullanmaktır.

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