neues Schlüsselwort in der Methodensignatur


113

Während eines Refactorings habe ich eine Methode wie das folgende Beispiel erstellt. Der Datentyp wurde der Einfachheit halber geändert.

Ich hatte vorher eine Zuweisungserklärung wie diese:

MyObject myVar = new MyObject();

Es wurde versehentlich umgestaltet:

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

Dies war das Ergebnis eines Fehlers beim Ausschneiden / Einfügen von meiner Seite, aber das newSchlüsselwort in private static newist gültig und wird kompiliert.

Frage : Was bedeutet das newSchlüsselwort in einer Methodensignatur? Ich nehme an, es ist etwas, das in C # 3.0 eingeführt wurde.

Wie unterscheidet sich das von override?


5
Einige Hinweise zur Wünschbarkeit des Versteckens von Methoden: blogs.msdn.com/ericlippert/archive/2008/05/21/…
Eric Lippert

2
@ Eric .. Toller Beitrag. Ich habe nie daran gedacht, dass sich eine Methode auf diese Weise versteckt, wie in Ja, das Objekt ist eine Sache, aber wir präsentieren es jetzt als etwas anderes, also wollen wir das Verhalten der Sache, als die wir es präsentieren. Clever ...
BFree

1
Eine doppelte Frage in der Zukunft und ich habe versucht, im Detail zu beantworten: Verwenden Sie neues Schlüsselwort in c #
Ken Kin

1
Die Verwendung eines newModifikators als aa für eine Methode (oder ein anderes Element) ist nicht "etwas, das in C # 3.0 eingeführt wurde". Es ist seit der ersten Version von C # da.
Jeppe Stig Nielsen

1
Es gibt ungefähr 4 Duplikate dieser Frage in SO. Meiner Meinung nach wird dies Ihnen das beste Verständnis vermitteln: stackoverflow.com/questions/3117838/… . Es wird von @EricLippert beantwortet.
Raikol Amaro

Antworten:


101

Neue Keyword-Referenz von MSDN:

MSDN-Referenz

Hier ist ein Beispiel, das ich im Internet von einem Microsoft MVP gefunden habe, das Sinn gemacht hat: Link zum 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

Override kann nur in ganz bestimmten Fällen verwendet werden. Von MSDN:

Sie können eine nicht virtuelle oder statische Methode nicht überschreiben. Die überschriebene Basismethode muss virtuell, abstrakt oder überschrieben sein.

Daher wird das Schlüsselwort "new" benötigt, damit Sie nicht virtuelle und statische Methoden "überschreiben" können.


4
Ich führe nur dein Sample aus. Es wird überschrieben, auch wenn du nicht "neu" spezifizierst, oder?
Michael Sync

2
@MichaelSync genau, warum müssen wir also ein neues Schlüsselwort erwähnen?
ZoomIn

2
"Obwohl Sie Mitglieder ausblenden können, ohne den neuen Modifikator zu verwenden, erhalten Sie eine Compiler-Warnung." gemäß dem verknüpften Dokument. Das Schlüsselwort macht also deutlich, dass Sie das Verstecken beabsichtigt haben, und die Warnung wird nicht ausgegeben.
Jim zählt

1
-1 -> es ist überhaupt nicht erforderlich - das Verhalten wird das gleiche sein. Sehr verwirrend für einen Neuling, worum es newgeht, aber ich denke, es ist buchstäblich nur zur besseren Lesbarkeit da - der Compiler warnt Sie lediglich, dass Sie beim Aufrufen einer abgeleiteten Klassenmethode mit demselben Namen wie base nicht die Methode der Basisklasse erhalten, die Sie möglicherweise erhalten Denken Sie ... es ist bizarr ... nur zur besseren Lesbarkeit?
Don Cheadle

1
Der Vollständigkeit halber: Wenn sowohl die A- als auch die B-Klasse eine Schnittstelle IMyInterfaceimplementieren, wird die Implementierung in der Derived-Klasse aufgerufen. Somit IMyInterface c = new B()wird die Implementierung der B-Klasse aufgerufen. Wenn nur eine Klasse die Schnittstelle implementiert, wird die Methode der Klasse aufgerufen, die sie implementiert.
Nullius

61

Nein, es ist eigentlich nicht "neu" (entschuldigen Sie das Wortspiel). Es wird im Grunde genommen verwendet, um eine Methode zu "verstecken". IE:

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

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

Wenn Sie dann dies tun:

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

Die Methode in der Base wird aufgerufen, NICHT die in der abgeleiteten.

Weitere Informationen: http://www.akadia.com/services/dotnet_polymorphism.html

Zu Ihrer Bearbeitung: In dem Beispiel, das ich gegeben habe, wenn Sie "überschreiben" anstatt "neu" zu verwenden, dann, wenn Sie b.Method () aufrufen; Die Methode der abgeleiteten Klasse würde wegen Polymorphismus aufgerufen.


öffentliche Klasse Base {public virtual void Method () {Console.WriteLine ("Base"); }} public class Abgeleitet: Base {public void Method () {Console.WriteLine ("Derived"); }} Basis b = new Derived (); b.Method (); Ich habe "Base". Wenn ich "neu" in der abgeleiteten Klasse hinzufüge, bekomme ich immer noch "Base".
Michael Sync

@ Michael die Methode ist noch virtuell
Rune FS

@MichaelSync: Sie sollten eine Warnung mit diesem Code sehen; Warnung Derived.Method () 'verbirgt das geerbte Mitglied' Base.Method () '. Fügen Sie das Schlüsselwort override hinzu, damit das aktuelle Mitglied diese Implementierung überschreibt. Andernfalls fügen Sie das neue Schlüsselwort hinzu.
Christopher McAtackney

2
@MichaelSync Wenn das Wort "Überschreiben" weggelassen wird, ist das Standardverhalten "Neu", z. B. Ausblenden von Methoden. Die Tatsache, dass Sie das Wort neu auslassen, macht also keinen Unterschied.
BFree

1
Ja. Das denke ich auch. Ich bin
Michael Sync

22

Wie andere erklärt haben, wird es verwendet, um eine vorhandene Methode auszublenden. Dies ist nützlich, um eine Methode zu überschreiben, die in der übergeordneten Klasse nicht virtuell ist.

Beachten Sie, dass das Erstellen eines "neuen" Elements nicht polymorph ist. Wenn Sie das Objekt in den Basistyp umwandeln, wird das Mitglied des abgeleiteten Typs nicht verwendet.

Wenn Sie eine Basisklasse haben:

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

Und dann die abgeleitete Klasse:

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

}

Wenn Sie einen Typ von deklarieren DerivedTypeund dann umwandeln, ist die Methode DoSomething()nicht polymorph, sondern ruft die Methode der Basisklasse auf, nicht die abgeleitete.

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

1
Es wird die Methode aus der Basisklasse aufrufen, auch wenn Sie "neu" aus DerievedType entfernen.
Michael Sync

2
Ich denke, Ihr zweiter Absatz befasst sich mit diesem gesamten Thema. Bei Aufrufen von einer Basisklassenreferenz ist "neu" nicht polymorph ... dh. Sie erhalten genau das, was Sie beim Tätigen des Anrufs angeben. "Override" ist polymorph ... dh. Sie erhalten, was die Klassenhierarchie angibt.
Jonathon Reinhart

Wie ist das so vage definiert? Sehr frustrierend für einen Neuling. Und nein, es hat nichts mit Polymorphismus zu tun - es hat genau das gleiche Verhalten wie einfach nicht overridein der Methodensignatur
Don Cheadle

Was ist vor was verborgen? Es kann sicher nicht sein, dass newder Basistyp vor dem abgeleiteten Typ verborgen ist, weil Sie nicht immer mit der base.<type>Notation auf den Basistyp zugreifen können ?
thatWiseGuy

@thatWiseGuy Es ist "versteckt" in dem Sinne, dass die Basismethode nicht aufgerufen wird, wenn die abgeleitete Klasse in Ihrem Code verwendet wird. Es kann weiterhin intern mit aufgerufen werden base.<method>und kann auch extern aufgerufen werden, wenn Sie den Basistyp in Ihrem Code umwandeln. Es ist technisch genauer, sich vorzustellen, dass die Basismethode "überschrieben" wird, als dass sie "versteckt" wird.
Dan Herbert

7

Aus den Dokumenten:

Wenn der Methode in der abgeleiteten Klasse das neue Schlüsselwort vorangestellt wird, wird die Methode als unabhängig von der Methode in der Basisklasse definiert.

Was dies in der Praxis bedeutet:

Wenn Sie von einer anderen Klasse erben und über eine Methode verfügen, die dieselbe Signatur verwendet, können Sie sie als "neu" definieren, damit sie unabhängig von der übergeordneten Klasse ist. Dies bedeutet, dass diese Implementierung ausgeführt wird, wenn Sie einen Verweis auf die übergeordnete Klasse haben. Wenn Sie einen Verweis auf die untergeordnete Klasse haben, wird diese Implementierung ausgeführt.

Persönlich versuche ich, das 'neue' Schlüsselwort zu vermeiden, da es normalerweise bedeutet, dass meine Klassenhierarchie falsch ist, aber es gibt Zeiten, in denen es nützlich sein kann. Ein Ort ist für die Versionierung und Abwärtskompatibilität.

Dafür gibt es im MSDN viele Informationen .


Die Tatsache, dass dieses Verhalten auftritt, hat nichts damit zu tun new, dort zu sein. Es ist syntaktisch / lesbar.
Don Cheadle

3

Dies bedeutet, dass die Methode eine Methode mit demselben Namen ersetzt, die von der Basisklasse geerbt wurde. In Ihrem Fall haben Sie wahrscheinlich keine Methode mit diesem Namen in der Basisklasse, was bedeutet, dass das neue Schlüsselwort völlig überflüssig ist.


3

Lange Rede, kurzer Sinn - es ist NICHT erforderlich, es ändert KEIN Verhalten und es ist REIN für die Lesbarkeit da.

Aus diesem Grund werden Sie in VS ein wenig schnörkellos sehen, aber Ihr Code wird kompiliert und läuft einwandfrei und wie erwartet.

Man muss sich fragen, ob es sich wirklich gelohnt hat, das newSchlüsselwort zu erstellen, wenn der Entwickler lediglich bestätigt: "Ja, ich weiß, dass ich eine Basismethode verstecke, ja, ich weiß, dass ich nichts im Zusammenhang mit virtualoder overriden(Polymorphismus) mache. Ich möchte wirklich nur eine eigene Methode erstellen ".

Es ist ein bisschen bizarr für mich, aber vielleicht nur, weil ich aus einem JavaHintergrund komme und es diesen grundlegenden Unterschied zwischen C#Vererbung und Java: In gibt Java, sind Methoden standardmäßig virtuell, sofern nicht anders angegeben final. In C#sind Methoden standardmäßig final / konkret, sofern nicht anders angegeben virtual.


1

Von MSDN :

Verwenden Sie den neuen Modifikator, um ein von einer Basisklasse geerbtes Mitglied explizit auszublenden. Um ein geerbtes Mitglied auszublenden, deklarieren Sie es in der abgeleiteten Klasse mit demselben Namen und ändern Sie es mit dem neuen Modifikator.


0

Sei vorsichtig mit diesem Gotcha.
Sie haben eine Methode in einer Schnittstelle definiert, die in einer Basisklasse implementiert ist. Anschließend erstellen Sie eine abgeleitete Klasse, die die Methode der Schnittstelle verbirgt, die abgeleitete Klasse jedoch nicht speziell als Implementierung der Schnittstelle deklariert. Wenn Sie die Methode dann über einen Verweis auf die Schnittstelle aufrufen, wird die Methode der Basisklasse aufgerufen. Wenn Ihre abgeleitete Klasse die Schnittstelle jedoch speziell implementiert, wird ihre Methode unabhängig von der verwendeten Referenzart aufgerufen.

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

    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.