new słowo kluczowe w sygnaturze metody

113

Podczas refaktoryzacji stworzyłem metodę taką jak na poniższym przykładzie. Typ danych został zmieniony ze względu na prostotę.

Wcześniej miałem takie oświadczenie przydziału:

MyObject myVar = new MyObject();

Zostało to refaktoryzowane przez przypadek:

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

Było to wynikiem mojego błędu wycinania / wklejania, ale newsłowo kluczowe w private static newjest prawidłowe i się kompiluje.

Pytanie : Co oznacza newsłowo kluczowe w sygnaturze metody? Zakładam, że to coś, co zostało wprowadzone w C # 3.0?

Czym to się różni override?

p.campbell
źródło
5
Kilka uwag na temat celowości ukrywania metod: blogs.msdn.com/ericlippert/archive/2008/05/21/…
Eric Lippert
2
@Eric .. Świetny post. Nigdy nie myślałem o metodzie ukrywania się w ten sposób, bo tak, obiekt JEST jedną rzeczą, ale teraz przedstawiamy go jako coś innego, więc chcemy zachować zachowanie rzeczy, którą prezentujemy JAKO. Clever ...
BFree
1
W przyszłości zduplikowane pytanie, na które próbowałem odpowiedzieć bardziej szczegółowo: Użyj nowego słowa kluczowego w języku c #
Ken Kin
1
Użycie newjako modyfikatora aa w metodzie (lub innym elemencie członkowskim typu) nie jest „czymś wprowadzonym w języku C # 3.0”. Jest tam od pierwszej wersji C #.
Jeppe Stig Nielsen,
1
W SO są jakieś 4 duplikaty tego pytania. Moim zdaniem ten daje najlepsze zrozumienie: stackoverflow.com/questions/3117838/… . Odpowiada @EricLippert.
Raikol Amaro

Odpowiedzi:

101

Nowe odniesienie do słów kluczowych z MSDN:

Dokumentacja MSDN

Oto przykład, który znalazłem w sieci od MVP firmy Microsoft, który miał sens: Link do oryginału

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

Zastąpienia można używać tylko w bardzo szczególnych przypadkach. Z MSDN:

Nie można przesłonić metody niewirtualnej ani statycznej. Zastąpiona metoda podstawowa musi być wirtualna, abstrakcyjna lub nadpisana.

Zatem słowo kluczowe „new” jest potrzebne, aby umożliwić „przesłonięcie” metod niewirtualnych i statycznych.

Kelsey
źródło
4
po prostu uruchomię twoją próbkę .. to zastąpi nawet jeśli nie określisz "nowy", prawda?
Michael Sync,
2
@MichaelSync dokładnie, dlaczego więc musimy wspomnieć o nowym słowie kluczowym?
ZoomIn
2
„Chociaż możesz ukrywać członków bez używania nowego modyfikatora, pojawi się ostrzeżenie kompilatora”. w połączonym dokumencie. Tak więc słowo kluczowe jasno wskazuje, że zamierzałeś ukryć, a ostrzeżenie nie jest wyświetlane.
Jim liczy
1
-1 -> nie jest to wcale wymagane - zachowanie będzie takie samo. Bardzo mylące dla początkującego, o co newchodzi, ale myślę, że jest to dosłownie tylko dla czytelności - kompilator po prostu ostrzega, że ​​kiedy wywołujesz metodę klasy pochodnej o tej samej nazwie co baza, nie otrzymasz metody klasy bazowej, którą możesz myślę ... to dziwne ... wyłącznie dla czytelności?
Don Cheadle
1
Ze względu na kompletność: Jeśli zarówno klasa A, jak i B implementują interfejs, IMyInterfacezostanie wywołana implementacja w klasie pochodnej. W ten sposób IMyInterface c = new B()zadzwoni implementacja klasy B. Jeśli tylko jedna klasa implementuje interfejs, zostanie wywołana metoda z klasy, która go implementuje.
Nullius
61

Nie, to właściwie nie jest „nowe” (przepraszam za kalambur). Zasadniczo jest używany do „ukrywania” metody. TO ZNACZY:

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

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

Jeśli to zrobisz:

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

Metoda w Base to ta, która zostanie wywołana, a NIE ta w wyprowadzonej.

Więcej informacji: http://www.akadia.com/services/dotnet_polymorphism.html

Re twoja edycja: W podanym przeze mnie przykładzie, gdybyś miał "przesłonić" zamiast używać "nowy", a następnie wywołać b.Method (); Metoda klasy pochodnej zostanie nazwana z powodu polimorfizmu.

BFree
źródło
public class Base {public virtual void Method () {Console.WriteLine ("Base"); }} klasa publiczna Pochodna: Base {public void Method () {Console.WriteLine ("Derived"); }} Base b = new Derived (); b.Method (); Otrzymałem „Podstawowy” .. Jeśli dodam „nowy” w klasie pochodnej, nadal otrzymuję „Podstawowy” ..
Michael Sync,
@michael, metoda jest nadal wirtualna
Rune FS
@MichaelSync: Powinieneś zobaczyć ostrzeżenie z tym kodem; Ostrzeżenie Derived.Method () 'ukrywa dziedziczony element członkowski' Base.Method () '. Aby bieżący element członkowski przesłaniał tę implementację, dodaj słowo kluczowe override. W przeciwnym razie dodaj nowe słowo kluczowe.
Christopher McAtackney,
2
@MichaelSync Jeśli słowo „override” zostanie pominięte, to domyślne zachowanie to „new”, np. Ukrywanie metody. Więc fakt, że zostawiasz słowo nowe, nie ma znaczenia.
BFree
1
Tak. Ja też tak myślę. Nie jestem pewien, dlaczego C # dodał słowo kluczowe „nowe” ... to tylko po to, aby zniknęło ostrzeżenie .. stackoverflow.com/questions/8502661/…
Michael Sync
22

Jak wyjaśnili inni, służy do ukrycia istniejącej metody. Jest to przydatne do przesłonięcia metody, która nie jest wirtualna w klasie nadrzędnej.

Pamiętaj, że tworzenie „nowego” elementu nie jest polimorficzne. Jeśli rzutujesz obiekt na typ podstawowy, nie będzie on używał elementu członkowskiego typu pochodnego.

Jeśli masz klasę bazową:

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

A następnie klasa pochodna:

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

}

Jeśli zadeklarujesz typ, DerivedTypea następnie go wyrzucisz, metoda DoSomething()nie jest polimorficzna, wywoła metodę klasy bazowej, a nie pochodną.

BaseClass t = new DerivedType();
t.DoSomething();// Calls the "DoSomething()" method of the base class.
Dan Herbert
źródło
1
Wywoła metodę z klasy bazowej, nawet jeśli usuniesz „new” z DerievedType.
Michael Sync,
2
Myślę, że twój drugi akapit jest zgodny z całym tematem. W przypadku wywołań z odwołania do klasy bazowej „nowy” nie jest polimorficzny… tj. Można dostać dokładnie to, co pan określić, kiedy nawiązać połączenie. „override” jest polimorficzne… tj. Otrzymasz to, co określa hierarchia klas .
Jonathon Reinhart
jak to jest tak niejasno zdefiniowane? Bardzo frustrujące dla początkującego. I nie, nie ma to nic wspólnego z polimorfizmem - zachowuje się dokładnie tak samo, jak po prostu brak overridew metodzie sygnatury
Don Cheadle
Co jest ukryte przed czym? Z pewnością nie może tak być, że newukrywa typ podstawowy przed typem pochodnym, ponieważ nie możesz zawsze uzyskać dostępu do typu podstawowego za pomocą base.<type>notacji?
thatWiseGuy
@thatWiseGuy Jest „ukryty” w tym sensie, że metoda podstawowa nie zostanie wywołana, gdy w kodzie używana jest klasa pochodna. Nadal można go wywoływać wewnętrznie przy użyciu base.<method>, a także zewnętrznie, jeśli rzutujesz na typ podstawowy w kodzie. Technicznie dokładniej jest myśleć o tym jako o „nadpisywaniu” metody podstawowej niż o „ukrywaniu” jej.
Dan Herbert,
7

Z dokumentów:

Jeśli metoda w klasie pochodnej jest poprzedzona słowem kluczowym new, metoda jest definiowana jako niezależna od metody w klasie bazowej.

Co to oznacza w praktyce:

Jeśli dziedziczysz z innej klasy i masz metodę, która ma ten sam podpis, możesz zdefiniować ją jako „nową”, aby była niezależna od klasy nadrzędnej. Oznacza to, że jeśli masz odwołanie do klasy „nadrzędnej”, to ta implementacja zostanie wykonana, jeśli masz odwołanie do klasy podrzędnej, to ta implementacja zostanie wykonana.

Osobiście staram się unikać słowa kluczowego „nowe”, ponieważ zwykle oznacza to, że mam błędną hierarchię klas, ale czasami może się to przydać. Jedno miejsce służy do wersjonowania i kompatybilności wstecznej.

W witrynie MSDN jest wiele informacji na ten temat .

jonnii
źródło
Fakt, że takie zachowanie występuje, nie ma nic wspólnego z newbyciem tam. To jest składnia / czytelność.
Don Cheadle
3

Oznacza to, że metoda zastępuje metodę o tej samej nazwie odziedziczonej przez klasę bazową. W twoim przypadku prawdopodobnie nie masz metody o tej nazwie w klasie bazowej, co oznacza, że ​​nowe słowo kluczowe jest całkowicie zbędne.

Robin Clowers
źródło
3

Krótko mówiąc - NIE jest to wymagane, NIE zmienia zachowania i jest CAŁKOWICIE tam dla czytelności.

Dlatego w VS zobaczysz trochę zawijanie, ale twój kod będzie kompilował się i działał idealnie dobrze i zgodnie z oczekiwaniami.

Można się zastanawiać, czy naprawdę warto było stworzyć newsłowo kluczowe, skoro wszystko to oznacza, że ​​programista przyznał: „Tak, wiem, że ukrywam metodę podstawową, tak wiem, że nie robię nic związanego z virtuallub overriden(polimorfizm) - Naprawdę chcę po prostu stworzyć własną metodę ”.

Jest to dla mnie trochę dziwne, ale może tylko dlatego, że pochodzę z Javatła i istnieje podstawowa różnica między C#dziedziczeniem a Java: W Javametodach są domyślnie wirtualne, chyba że określono to w final. W programie C#metody są domyślnie końcowe / konkretne, chyba że określono to w virtual.

Don Cheadle
źródło
1

Z MSDN :

Użyj nowego modyfikatora, aby jawnie ukryć element członkowski odziedziczony z klasy bazowej. Aby ukryć dziedziczony element członkowski, zadeklaruj go w klasie pochodnej przy użyciu tej samej nazwy i zmodyfikuj go za pomocą nowego modyfikatora.

Doug R.
źródło
0

Uważaj na tę łapkę.
Masz metodę zdefiniowaną w interfejsie, który jest zaimplementowany w klasie bazowej. Następnie tworzysz klasę pochodną, ​​która ukrywa metodę interfejsu, ale nie deklarujesz konkretnie klasy pochodnej jako implementującej interfejs. Jeśli następnie wywołasz metodę za pośrednictwem odwołania do interfejsu, zostanie wywołana metoda klasy bazowej. Jeśli jednak klasa pochodna konkretnie implementuje interfejs, jej metoda zostanie wywołana niezależnie od używanego typu odwołania.

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

    }
}
Przepełniona kamizelka
źródło