nuova parola chiave nella firma del metodo


113

Durante l'esecuzione di un refactoring, ho finito per creare un metodo come nell'esempio seguente. Il tipo di dati è stato modificato per semplicità.

In precedenza avevo una dichiarazione di incarico come questa:

MyObject myVar = new MyObject();

È stato modificato per questo per caso:

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

Questo è stato il risultato di un errore di copia / incolla da parte mia, ma la newparola chiave in private static newè valida e viene compilata.

Domanda : cosa significa la newparola chiave nella firma di un metodo? Presumo sia qualcosa di introdotto in C # 3.0?

In che cosa differisce override?


5
Alcune note sull'opportunità di nascondere il metodo: blogs.msdn.com/ericlippert/archive/2008/05/21/…
Eric Lippert

2
@Eric .. Ottimo post. Non ho mai pensato al metodo che si nasconde in quel modo, perché sì, l'oggetto È una cosa, ma ora lo stiamo presentando come qualcos'altro, quindi vogliamo il comportamento della cosa che lo presentiamo COME. Clever ...
BFree

1
Una domanda duplicata in futuro e ho provato a rispondere in dettaglio: Usa nuova parola chiave in c #
Ken Kin

1
L'uso di newcome modificatore aa su un metodo (o un altro membro di tipo) non è "qualcosa di introdotto in C # 3.0". È presente sin dalla prima versione di C #.
Jeppe Stig Nielsen

1
Ci sono circa 4 duplicati di questa domanda in SO. Secondo me, questo ti darà la migliore comprensione: stackoverflow.com/questions/3117838/… . È risposto da @EricLippert.
Raikol Amaro

Risposte:


101

Nuovo riferimento alle parole chiave da MSDN:

Riferimento MSDN

Ecco un esempio che ho trovato in rete da un Microsoft MVP che aveva un buon senso: 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

Override può essere utilizzato solo in casi molto specifici. Da MSDN:

Non è possibile sovrascrivere un metodo non virtuale o statico. Il metodo di base sottoposto a override deve essere virtual, abstract o override.

Quindi la parola chiave "new" è necessaria per consentire di "sovrascrivere" metodi non virtuali e statici.


4
ho appena eseguito il tuo campione .. sovrascriverà anche se non specifichi "nuovo", giusto?
Michael Sync

2
@MichaelSync esattamente, quindi perché dobbiamo menzionare una nuova parola chiave?
ZoomIn

2
"Sebbene sia possibile nascondere i membri senza utilizzare il nuovo modificatore, viene visualizzato un avviso del compilatore." per il documento collegato. Quindi, la parola chiave chiarisce che si intendeva nascondersi e l'avvertimento non viene emesso.
Jim conta il

1
-1 -> non è affatto richiesto - il comportamento sarà lo stesso. Molto confuso per un principiante di cosa newsi tratta, ma penso che sia letteralmente solo per leggibilità: il compilatore ti avverte semplicemente che quando chiami il metodo della classe derivata con lo stesso nome di base, non otterrai il metodo della classe base che potresti pensa .... è bizzarro ... puramente per leggibilità?
Don Cheadle

1
Per ragioni di completezza: se entrambe le classi A e B implementano un'interfaccia, IMyInterfaceverrà chiamata l'implementazione sulla classe Derived. Così IMyInterface c = new B()chiamerà l'implementazione della classe B. Se solo una classe implementa l'interfaccia, verrà chiamato il metodo della classe che la implementa.
Nullius

61

No, in realtà non è "nuovo" (scusate il gioco di parole). Fondamentalmente è usato per "nascondere" un metodo. IE:

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

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

Se poi fai questo:

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

Il metodo in Base è quello che verrà chiamato, NON quello in derivato.

Qualche info in più: http://www.akadia.com/services/dotnet_polymorphism.html

Per la tua modifica: Nell'esempio che ho fornito, se dovessi "sovrascrivere" invece di usare "new", quando chiami b.Method (); il metodo della classe derivata verrebbe chiamato a causa del polimorfismo.


public class Base {public virtual void Method () {Console.WriteLine ("Base"); }} public class Derived: Base {public void Method () {Console.WriteLine ("Derived"); }} Base b = new Derived (); b.Method (); Ho "Base" .. Se aggiungo "nuovo" nella classe derivata, ottengo ancora "Base" ..
Michael Sync

@michael il metodo è ancora virtuale
Rune FS

@MichaelSync: dovresti vedere un avviso con quel codice; Avviso Derived.Method () 'nasconde il membro ereditato' Base.Method () '. Per fare in modo che il membro corrente sovrascriva tale implementazione, aggiungi la parola chiave override. Altrimenti aggiungi la nuova parola chiave.
Christopher McAtackney

2
@MichaelSync Se la parola "override" viene omessa, il comportamento predefinito è "new", ad es. Metodo nascosto. Quindi il fatto che tu stia lasciando la parola nuova fuori non fa differenza.
BFree

1
Sì. È quello che penso anch'io. Non sono sicuro del motivo per cui C # abbia aggiunto la parola chiave "nuova" ... è solo per far scomparire l'avviso .. stackoverflow.com/questions/8502661/…
Michael Sync

22

Come altri hanno spiegato, viene utilizzato per nascondere un metodo esistente. È utile per sovrascrivere un metodo che non è virtuale nella classe genitore.

Tieni presente che la creazione di un "nuovo" membro non è polimorfica. Se si esegue il cast dell'oggetto nel tipo di base, non verrà utilizzato il membro del tipo derivato.

Se hai una classe base:

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

E poi la classe derivata:

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

}

Se dichiari un tipo di DerivedTypee poi lo esegui, il metodo DoSomething()non è polimorfico, chiamerà il metodo della classe base, non quello derivato.

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

1
Chiamerà il metodo dalla classe base anche se rimuovi "new" da DerievedType ..
Michael Sync

2
Penso che il tuo secondo paragrafo risolva l'intero argomento. Quando si ha a che fare con chiamate da un riferimento a una classe base , "new" non è polimorfico ... cioè. Ottieni esattamente ciò che specifichi quando effettui la chiamata. "override" è polimorfico ... cioè. Ottieni ciò che specifica la gerarchia delle classi .
Jonathon Reinhart

come è questo qualcosa di così vagamente definito? Molto frustrante per un principiante. E no, non ha nulla a che fare con il polimorfismo - ha lo stesso identico comportamento che semplicemente non ha la overridefirma del metodo
Don Cheadle,

Cosa si nasconde da cosa? Sicuramente non può essere che newnasconda il tipo di base dal tipo derivato, perché non puoi sempre accedere al tipo di base usando la base.<type>notazione?
thatWiseGuy

@thatWiseGuy È "nascosto" nel senso che il metodo di base non verrà chiamato quando si utilizza la classe derivata nel codice. Può ancora essere chiamato internamente usando base.<method>e può anche essere chiamato esternamente se si esegue il cast al tipo di base nel codice. È tecnicamente più accurato pensarlo come "sovrascrittura" del metodo di base piuttosto che "nasconderlo".
Dan Herbert

7

Dai documenti:

Se il metodo nella classe derivata è preceduto dalla nuova parola chiave, il metodo viene definito come indipendente dal metodo nella classe base.

Cosa significa in pratica:

Se erediti da un'altra classe e hai un metodo che condivide la stessa firma, puoi definirlo come "nuovo" in modo che sia indipendente dalla classe genitore. Ciò significa che se si dispone di un riferimento alla classe "genitore", tale implementazione verrà eseguita, se si dispone di un riferimento alla classe figlia, verrà eseguita tale implementazione.

Personalmente cerco di evitare la parola chiave "nuova" poiché normalmente significa che ho sbagliato la gerarchia delle classi, ma a volte può essere utile. Un posto è per il controllo delle versioni e la compatibilità con le versioni precedenti.

Ci sono molte informazioni in MSDN per questo .


Il fatto che si verifichi questo comportamento non ha nulla a che fare con la newpresenza. È sintattico / leggibilità.
Don Cheadle

3

Significa che il metodo sostituisce un metodo con lo stesso nome ereditato dalla classe base. Nel tuo caso, probabilmente non hai un metodo con quel nome nella classe base, il che significa che la nuova parola chiave è totalmente superflua.


3

Per farla breve: NON è richiesto, NON cambia NESSUN comportamento, ed è PURAMENTE lì per la leggibilità.

Ecco perché in VS vedrai un po 'ondulato, ma il tuo codice verrà compilato e funzionerà perfettamente e come previsto.

Ci si deve chiedere se valesse davvero la pena creare la newparola chiave quando tutto ciò che significa è che lo sviluppatore ha riconosciuto "Sì, lo so che sto nascondendo un metodo di base, sì, lo so che non sto facendo nulla relativo a virtualo overriden(polimorfismo) - Voglio davvero creare il proprio metodo ".

È un po 'bizzarro per me, ma forse solo perché provengo da un Javabackground e c'è questa differenza fondamentale tra C#ereditarietà e Java: In Java, i metodi sono virtuali per impostazione predefinita se non specificato da final. In C#, i metodi sono final / concrete per impostazione predefinita a meno che non sia specificato da virtual.


1

Da MSDN :

Usa il nuovo modificatore per nascondere in modo esplicito un membro ereditato da una classe base. Per nascondere un membro ereditato, dichiararlo nella classe derivata utilizzando lo stesso nome e modificarlo con il nuovo modificatore.


0

Stai attento a questo trucchetto.
Hai un metodo definito in un'interfaccia implementata in una classe base. Si crea quindi una classe derivata che nasconde il metodo dell'interfaccia, ma non si dichiara specificamente la classe derivata come implementazione dell'interfaccia. Se poi chiami il metodo tramite un riferimento all'interfaccia, verrà chiamato il metodo della classe base. Tuttavia, se la classe derivata implementa specificamente l'interfaccia, il suo metodo verrà chiamato a seconda del tipo di riferimento utilizzato.

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

    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.