C # 'da gölgeleme ile bir yöntemi geçersiz kılma arasındaki fark nedir ?
Yanıtlar:
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.
Umarım mantıklıyım :)
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.
Bence temel fark, gölgeleme ile aslında adı yeniden kullanıyorsunuz ve sadece süper sınıf kullanımını görmezden geliyorsunuz. Geçersiz kılarak, uygulamayı değiştirirsiniz, ancak erişilebilirliği ve imzayı değiştirmezsiniz (örn. Parametre türleri ve dönüş). Bkz. Http://www.geekinterview.com/question_details/19331 .
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.
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.
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();
}
}