C # 'daki “yeni” değiştiricinin gizleme açısından bazı pratik kullanımları nelerdir?


21

Bir meslektaşım ve ben newanahtar kelimenin C # 'daki davranışına gizlenme kavramı için geçerli olduğu gibi bakıyorduk . Gönderen belgeler :

Temel sınıftan miras kalan bir üyeyi açıkça gizlemek için yeni değiştiriciyi kullanın. Miras alınan bir üyeyi gizlemek için, aynı adı kullanarak türetilmiş sınıfta ilan edin ve yeni değiştiriciyle değiştirin.

Belgeleri okuduk ve temelde ne yaptığını ve nasıl yaptığını anlıyoruz. Gerçekten başa çıkamadığımız şey, neden en baştan yapmanız gerektiğine ilişkin. Değiştirici 2003'ten beri orada ve ikimizde .Net ile bundan daha uzun süredir birlikte çalışıyoruz ve asla ortaya çıkmadı.

Bu davranış ne zaman pratik anlamda gerekli olacaktır (örneğin: bir iş vakasına uygulandığı gibi)? Bu, kullanım ömrünü uzatan bir özellik mi, yoksa yaptığımız işte yeterince nadir görülen bir şey mi (özellikle web formları ve MVC uygulamaları ve bazı küçük faktörlü WinForms ve WPF yapıyoruz)? Bu anahtar kelimeyi denemek ve onunla oynamak, yanlış kullanılırsa bunun biraz tehlikeli görünmesine izin veren bazı davranışlar bulduk.

Bu kulağa biraz açık uçlu geliyor, ancak bu aracı yararlı bulabilen bir iş uygulamasına uygulanabilecek belirli bir kullanım durumu arıyoruz.


9
Belki de siz de okudunuz ama Eric Lippert'in (C # derleyici geliştiricisi) C #: blogs.msdn.com/b/ericlippert/archive/2008/05/21/… . Bu, sorunuzun bir kısmını cevaplar, ancak sizin için hazır bir iş vakam yok, bu yüzden bunu bir yorumuma koydum.
Jalayn

3
@ Jalayn: İş vakası bu yazıda Eric tarafından tartışılıyor: blogs.msdn.com/b/ericlippert/archive/2004/01/07/…
Brian

Yanıtlar:


22

Dönüş tipi kovaryansını taklit etmek için kullanabilirsiniz. Eric Lippert'in Açıklaması . Eric bu örnek kodu sağlar:

abstract class Enclosure
{
    protected abstract Animal GetContents();
    public Animal Contents() { return this.GetContents(); }
}
class Aquarium : Enclosure
{
    public new Fish Contents() { ... }
    protected override Animal GetContents() { return this.Contents(); }
}

Bu bir uğraş. public override Fish Contents() { ... }güvenli olmasına rağmen yasal değildir.

Genel olarak, gereken değil sizin sınıfın tüketicilere kafa karıştırıcı olarak (yukarıda spesifik bir örnek bu sorundan muzdarip değildir), yöntem gizlenmesini kullanın. Mevcut yöntemi geçersiz kılmak istemiyorsanız, yeni yönteminize başka bir şey adlandırın.

Yöntem gizlemesine ihtiyaç duyabileceğiniz gerçek dünyadaki bir durum, bir temel sınıfın sağlayıcısının türetilmiş bir sınıfa zaten eklediğiniz bir genel yöntem eklediğidir. Böyle bir program, yeni anahtar kelime olmadan derlenecek (ve uyarılar verecek), ancak ekliyor new: "Bu yöntemin sürümümün temel sınıfın versiyonunun yerini aldığını biliyorum. Bu korkunç ve kafa karıştırıcı, ancak bununla birlikte kaldık" diyor. Bu, türetilmiş sınıfı kendi yöntemini yeniden adlandırmaya zorlamaktan daha iyidir.

Sadece türetilmiş yöntemin geçersiz kılma olarak ele alınmasına izin vermek sorunlara yol açacaktır. Derleyicinin uygulanmasıyla ilgili endişeleri görmezden gelindiğinde, yeni yöntem temel yöntemden anlamsal olarak farklıdır, ancak polimorfizm aynı adı taşıyan bir yöntem çağrılması istendiğinde yeni yöntemin çağrılmasına neden olur.

Bu durum, bu yazıda Eric Lippert tarafından ayrıntılı olarak ele alınmıştır .


1
+1, new"bu korkunç ve kafa karıştırıcı" için bir işaretleyici olduğu için.
Avner Shahar-Kashtan

Bence Eric'in örneği çok faydalı, sadece benzer bir durumda olduğum için ... TBase iadesi için önemsiz bir yöntem uygulayan bir temel sınıfım ve TDerived iadesi gereken türetilmiş bir sınıfım var. Bu durumda, gerekli bir kötülük gibi hissediyor.
Kyle Baran

4

Dil tasarımcılarının düşünmemiş olabileceği bir şeyi yapmak için ihtiyaç duymanız gerekebileceğini düşünüyorum. C # birçok yönden java'nın ilk sürümlerine bir reaksiyon oldu. Ve java'nın yaptığı bir şey, kendilerini geliştirenlerin kendilerini ayaklarından vurma ihtimallerini ortadan kaldırmak için açık bir şekilde güvercin deliği geliştiricilerini yapmaktı. C # biraz farklı bir yaklaşım benimsemiş ve geliştiricilerin kendilerini ayaklarından vurmaları için birkaç fırsat daha sunmalarına biraz daha güç vermiştir. Bir örnek unsafeanahtar kelimedir. Bu newanahtar kelime başka.

Şimdi, muhtemelen kadar kullanışlı değil, unsafeancak bir dil spesifikasyonuna girdiğinizde bir dil spesifikasyonundan çıkmak zor.


5
Java, tüm yöntemleri sanal olarak ele aldığından dolayı yeni bir Java yoktur. Eric Lippert'e göre, yeniyi destekleme motivasyonu kırılgan temel sınıf problemini çözmektir. Yeniliğin varlığı sadece düşük seviyeli kütüphane kullanımı için değil, gerçek dünyadaki iş kullanımı için gereklidir. Java'nın yeni olmaması (ve sanal olmayan yöntemlerin olmaması), bir temel sınıfın türetilmiş sınıflar içinde zaten kullanılmış olan yeni bir yöntem getirmesi durumunda, temel sınıfın geliştiricisine izin verilmesi gerektiğine rağmen, mevcut kodun bozulabileceği anlamına gelir. tüketen koda uymamak.
Brian,

3

Bu, okuyucuya, kazara aksine, "temel sınıfı 'bu yöntemin uygulanmasını kasıtlı olarak sakladım" diyor.


5
Bu soruya yalvarırken beni etkiliyor. OP ne yaptığını biliyor ama nedenini bilmek istiyor.
Brian,

0

Önceki üyenin başka bir isim için uygun olmasını isteyebilirsiniz:

class VehicleClass
{
  public int AnyProperty
  {
    get; set;
  }

  public int AnyFunction() { return 0; }
} // VehicleClass

class IntermediateClass : VehicleClass
{
  public int PreviousAnyProperty
  {
    get { return AnyProperty; }
    set { AnyProperty = value  }
  }

  public int PreviousAnyFunction() { return AnyFunction(); }
} // IntermediateClass 

class CarClass : IntermediateClass
{
  public new int AnyProperty
  {
    get ; set ;
  }

  public new int AnyFunction() { return 5; }
} // class CarClass

class ExampleClass
{

  public static void Main()
  {
    using (CarClass MyCar = new CarClass())
    {
      int AnyInt1 = MyCar.PreviousAnyProperty;
      MyCar.PreviousAnyProperty = 7;

      int AnyInt2 = MyCar.PreviousAnyFunction();

      int AnyInt3 = MyCar.AnyProperty;
      MyCar.AnyProperty = 45;

      int AnyInt4 = MyCar.AnyFunction();
    }
  } // static void Main()

} // class CarClass

Şerefe.


Nasıl çalıştığını biliyorum, ama sorum şu: Neden önceki üyeye başka bir isim vermek istiyorsun? Bu her türlü sözleşmeyi keser, bazı jenerik parçaları işe yaramaz hale getirir.
Joel Etherton

@Joel Etherton: Bildiğiniz gibi, bazen geliştiriciler kod programlama yapan başkalarını "seçmek" zorundadırlar. Ve değiştirme, belki sınıfları genişletme yetkisi olmayabilir. Ve her ikisini de, önceki üyeyi ve yenisini kullanmayı gerektirebilir.
umlcat

0

Eski kod için bir test paketi oluştururken oldukça yararlı buldum. Başka yöntemler tarafından kullanılan bir yöntemin içindeki bir veritabanını sorgulamak gibi dış bağımlılıkları gizlememi sağlıyor. Diğer yöntemleri test edebilmek için, sanal anahtar kelimeyi test sınıflarındaki yöntemlere eklemek zorunda kalmadan dış kaynaklara bağlı olan orijinal mantığı gizleyebilirim.

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.