yöntem imzasında yeni anahtar kelime


113

Yeniden düzenleme yaparken, aşağıdaki örnekteki gibi bir yöntem oluşturdum. Veri türü basitlik uğruna değiştirildi.

Daha önce şöyle bir atama bildirimim vardı:

MyObject myVar = new MyObject();

Bu duruma tesadüfen yeniden düzenlenmiştir:

private static new MyObject CreateSomething()
{
  return new MyObject{"Something New"};
}

Bu benim açımdan bir kesme / yapıştırma hatasının bir sonucuydu, ancak in newanahtar kelimesi private static newgeçerlidir ve derlenir.

Soru : newAnahtar sözcük, yöntem imzasında neyi ifade eder ? C # 3.0'da tanıtılan bir şey olduğunu varsayıyorum?

Bu nasıl farklıdır override?


5
Yöntem gizlemenin istenebilirliği hakkında bazı notlar: blogs.msdn.com/ericlippert/archive/2008/05/21/…
Eric Lippert

2
@Eric .. Harika gönderi. Yöntemin bu şekilde saklanmasını hiç düşünmemiştim, çünkü evet, nesne bir şeydir, ama şimdi onu başka bir şey olarak sunuyoruz, bu yüzden onu OLARAK sunduğumuz şeyin davranışını istiyoruz. Zekice ...
BFree

1
Gelecekte yinelenen bir soru ve biraz ayrıntılı olarak yanıtlamayı denedim: c # içinde yeni anahtar kelime kullanın
Ken Kin

1
newBir yöntemde (veya başka tür bir üye) bir değiştirici olarak kullanımı "C # 3.0'da tanıtılan bir şey" değildir. C # 'ın ilk sürümünden beri oradaydı.
Jeppe Stig Nielsen

1
SO'da bu sorunun 4 kopyası var. Bana göre, bu size en iyi anlayışı sağlayacaktır: stackoverflow.com/questions/3117838/… . @EricLippert tarafından yanıtlanır.
Raikol Amaro

Yanıtlar:


101

MSDN'den yeni anahtar kelime referansı:

MSDN Referansı

İşte bir Microsoft MVP'den internette bulduğum iyi bir örnek: Link to Original

public class A
{
   public virtual void One();
   public void Two();
}

public class B : A
{
   public override void One();
   public new void Two();
}

B b = new B();
A a = b as A;

a.One(); // Calls implementation in B
a.Two(); // Calls implementation in A
b.One(); // Calls implementation in B
b.Two(); // Calls implementation in B

Geçersiz kılma yalnızca çok özel durumlarda kullanılabilir. MSDN'den:

Sanal olmayan veya statik bir yöntemi geçersiz kılamazsınız. Geçersiz kılınan temel yöntem sanal, soyut veya geçersiz kılma olmalıdır.

Dolayısıyla, sanal olmayan ve statik yöntemleri "geçersiz kılmanıza" izin vermek için "yeni" anahtar kelimesine ihtiyaç vardır.


4
Ben sadece örneğinizi çalıştırıyorum .. "yeni" yi belirtmeseniz bile geçersiz kılar, değil mi?
Michael Sync

2
@MichaelSync, öyleyse neden yeni anahtar kelimeden bahsetmemiz gerekiyor?
ZoomIn

2
"Yeni değiştiriciyi kullanmadan üyeleri gizleyebilmenize rağmen, bir derleyici uyarısı alırsınız." bağlantılı dokümana göre. Bu nedenle, anahtar kelime gizlemeyi amaçladığınız ve uyarı verilmez.
Jim

1
-1 -> hiç gerekli değil - davranış aynı olacaktır. Bir acemi için çok kafa karıştırıcı new, ama bence kelimenin tam anlamıyla sadece okunabilirlik için var - derleyici basitçe sizi uyarıyor, temel olarak aynı adı taşıyan türetilmiş sınıf yöntemini çağırdığınızda, yapabileceğiniz temel sınıfın yöntemini alamayacaksınız düşünmek .... tuhaf ... sadece okunabilirlik için?
Don Cheadle

1
Tamlık adına: Hem A hem de B sınıfı bir arabirim IMyInterfaceuygularsa, Derived sınıfındaki uygulama çağrılır. Böylece IMyInterface c = new B()B sınıfının uygulanmasını çağıracak. Arabirimi yalnızca bir sınıf uygularsa, onu uygulayan sınıfın yöntemi çağrılır.
Nullius

61

Hayır, aslında "yeni" değil (kelime oyununu bağışlayın). Temelde bir yöntemi "gizlemek" için kullanılır. IE:

public class Base
{
   public virtual void Method(){}
}

public class Derived : Base
{
   public new void Method(){}
}

Bunu yaparsanız:

Base b = new Derived();
b.Method();

Base'deki yöntem, türetilen yöntem DEĞİL, çağrılacak olan yöntemdir.

Biraz daha bilgi: http://www.akadia.com/services/dotnet_polymorphism.html

Düzenlemeniz yeniden: Verdiğim örnekte, "yeni" yerine "geçersiz kılmak" olsaydı, o zaman b.Method () 'u çağırdığınızda; Türetilmiş sınıfın Yöntemi, Polimorfizm nedeniyle çağrılır.


public class Base {public virtual void Method () {Console.WriteLine ("Base"); }} public class Türetilmiş: Base {public void Method () {Console.WriteLine ("Türetilmiş"); }} Temel b = yeni Türetilmiş (); b.Method (); "Temel" aldım .. Türetilmiş sınıfa "yeni" eklersem, yine de "Temel" elde ederim ..
Michael Sync

@michael yöntem hala sanal
Rune FS

@MichaelSync: Bu kodla bir uyarı görüyor olmalısınız; Uyarı Derived.Method () ', miras alınan' Base.Method () 'üyesini gizler. Geçerli üyenin bu uygulamayı geçersiz kılmasını sağlamak için override anahtar sözcüğünü ekleyin. Aksi takdirde yeni anahtar kelimeyi ekleyin.
Christopher McAtackney

2
@MichaelSync "Geçersiz kılma" sözcüğü dışarıda bırakılırsa, varsayılan davranış "yeni" olur, örneğin yöntem gizleme. Yani yeni kelimesini dışarıda bırakmanızın hiçbir önemi yok.
BFree

1
Evet. Ben de öyle düşünüyorum. C # 'nın neden "yeni" anahtar kelime eklediğinden emin değilim .. sadece uyarıyı ortadan kaldırmak için .. stackoverflow.com/questions/8502661/…
Michael Sync

22

Diğerlerinin açıkladığı gibi, mevcut bir yöntemi gizlemek için kullanılır. Üst sınıfta sanal olmayan bir yöntemi geçersiz kılmak için kullanışlıdır.

"Yeni" bir üye oluşturmanın polimorfik olmadığını unutmayın. Nesneyi temel türe çevirirseniz, türetilmiş türün üyesini kullanmaz.

Temel bir sınıfınız varsa:

public class BaseClass
{
    public void DoSomething() { }
}

Ve sonra türetilmiş sınıf:

public class DerivedType : BaseClass
{
    public new void DoSomething() {}

}

Bir tür bildirir DerivedTypeve sonra onu DoSomething()çevirirseniz, yöntem polimorfik değildir, türetilmiş olanı değil, temel sınıfın yöntemini çağırır.

BaseClass t = new DerivedType();
t.DoSomething();// Calls the "DoSomething()" method of the base class.

1
DerievedType'tan "yeni" yi de kaldırsanız bile, yöntemi temel sınıftan çağırır ..
Michael Sync

2
Sanırım ikinci paragrafınız tüm konuyu etkiliyor. Bir temel sınıf referansından gelen çağrılar ile uğraşırken , "yeni" polimorfik değildir ... yani. Sen tam olarak ne olsun sen çağrıyı yaparken belirtin. "geçersiz kılma" polimorfiktir ... yani. Sınıf hiyerarşisinin belirlediğini alırsınız .
Jonathon Reinhart

bu nasıl belirsiz bir şekilde tanımlanmış bir şey? Bir acemi için çok sinir bozucu. Ve hayır, polimorfizmle hiçbir ilgisi yok - overrideyöntem imzasının olmamasıyla aynı davranışa sahip
Don Cheadle

Neyden gizlenen nedir? newTemel türü türetilmiş türden gizleyen kesinlikle olamaz , çünkü base.<type>gösterimi kullanarak temel türe her zaman erişemez misiniz ?
thatWiseGuy

@thatWiseGuy Kodunuzda türetilmiş sınıfı kullanırken temel yöntemin çağrılmaması anlamında "gizlidir". Hala kullanılarak dahili olarak çağrılabilir base.<method>ve kodunuzda temel türe çevirirseniz harici olarak da çağrılabilir. Temel yöntemi "gizlemek" yerine "geçersiz kıldığını" düşünmek teknik olarak daha doğrudur.
Dan Herbert

7

Dokümanlardan:

Türetilmiş sınıftaki yöntemin önünde new anahtar sözcüğü varsa, yöntem temel sınıftaki yöntemden bağımsız olarak tanımlanır.

Pratikte bunun anlamı:

Başka bir sınıftan miras alırsanız ve aynı imzayı paylaşan bir yönteminiz varsa, ana sınıftan bağımsız olması için onu 'yeni' olarak tanımlayabilirsiniz. Bu, eğer 'ebeveyn' sınıfa bir referansınız varsa, bu uygulamanın çalıştırılacağı, alt sınıfa bir referansınız varsa bu uygulamanın çalıştırılacağı anlamına gelir.

Kişisel olarak, normal olarak sınıf hiyerarşimi yanlış anladığım anlamına geldiği için 'yeni' anahtar kelimesini kullanmamaya çalışıyorum, ancak bazen yararlı olabileceği zamanlar oluyor. Bir yer, sürüm oluşturma ve geriye dönük uyumluluk içindir.

MSDN'de bunun için pek çok bilgi var .


Bu davranışın meydana gelmesinin neworada olmakla hiçbir ilgisi yoktur. Sözdizimsel / okunabilirliktir.
Don Cheadle

3

Bu, yöntemin, temel sınıf tarafından miras alınan aynı ada sahip bir yöntemi değiştirdiği anlamına gelir. Sizin durumunuzda, muhtemelen temel sınıfta bu isimde bir yönteme sahip değilsiniz, yani yeni anahtar kelime tamamen gereksizdir.


3

Uzun lafın kısası - gerekli DEĞİLDİR, HİÇBİR davranışı değiştirmez ve okunabilirlik için PURELY oradadır.

Bu nedenle VS'de biraz dalgalı göreceksiniz, ancak kodunuz beklendiği gibi mükemmel bir şekilde derlenecek ve çalışacaktır.

newGeliştiricinin "Evet, temel bir yöntemi sakladığımı biliyorum, evet virtualveya overriden(polimorfizm) ile ilgili hiçbir şey yapmadığımı biliyorum, bunun anlamı anahtar kelimeyi oluşturmanın gerçekten değip değmeyeceğini merak etmek gerekir. Gerçekten sadece kendi yöntemini yaratmak istiyorum ".

Bu benim için biraz tuhaf ama belki de Javaarka plandan geldiğim için ve C#kalıtım ile kalıtım arasında şu temel fark var Java: İçinde Java, tarafından belirtilmedikçe yöntemler varsayılan olarak sanaldır final. İçinde C#, tarafından belirtilmedikçe yöntemler varsayılan olarak nihai / somuttur virtual.


1

Gönderen MSDN :

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


0

Bu şeye dikkat et.
Bir temel sınıfta uygulanan bir arabirimde tanımlanan bir yönteminiz var. Ardından, arabirimin yöntemini gizleyen türetilmiş bir sınıf oluşturursunuz, ancak türetilmiş sınıfı özellikle arabirimi uygularken bildirmezsiniz. Daha sonra yöntemi arabirime bir başvuru yoluyla çağırırsanız, temel sınıfın yöntemi çağrılır. Bununla birlikte, türetilmiş sınıfınız arabirimi özel olarak uygularsa, hangi başvuru türü kullanılırsa kullanılsın, yöntemi çağrılacaktır.

interface IMethodToHide
{
    string MethodToHide();
}

class BaseWithMethodToHide : IMethodToHide
{
    public string MethodToHide()
    {
        return "BaseWithMethodToHide";
    }
}

class DerivedNotImplementingInterface   : BaseWithMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedNotImplementingInterface";
    }
}

class DerivedImplementingInterface : BaseWithMethodToHide, IMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedImplementingInterface";
    }
}

class Program
{
    static void Main()
    {
        var oNoI = new DerivedNotImplementingInterface();
        IMethodToHide ioNoI = new DerivedNotImplementingInterface();

        Console.WriteLine("reference to the object type DerivedNotImplementingInterface calls the method in the class " 
            + oNoI.MethodToHide());
        // calls DerivedNotImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedNotImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioNoI.MethodToHide());
        // calls BaseWithMethodToHide.MethodToHide()
        Console.ReadLine();

        var oI = new DerivedImplementingInterface();
        IMethodToHide ioI = new DerivedImplementingInterface();

        Console.WriteLine("reference to the object type DerivedImplementingInterface calls the method in the class " 
            + oI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.ReadLine();

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