È ansible sovrascrivere un metodo non virtuale?

C’è un modo per sovrascrivere un metodo non virtuale? o qualcosa che dia risultati simili (oltre a creare un nuovo metodo per chiamare il metodo desiderato)?

Vorrei sovrascrivere un metodo da Microsoft.Xna.Framework.Graphics.GraphicsDevice con test delle unità in mente.

No, non è ansible sovrascrivere un metodo non virtuale. La cosa più vicina che puoi fare è hide il metodo creando un new metodo con lo stesso nome, ma questo non è consigliabile in quanto rompe i principi del buon design.

Ma anche hide un metodo non ti darà un invio polimorfico del tempo di esecuzione delle chiamate di metodo come farebbe una vera chiamata al metodo virtuale. Considera questo esempio:

 using System; class Example { static void Main() { Foo f = new Foo(); fM(); Foo b = new Bar(); bM(); } } class Foo { public void M() { Console.WriteLine("Foo.M"); } } class Bar : Foo { public new void M() { Console.WriteLine("Bar.M"); } } 

In questo esempio, entrambe le chiamate al metodo M stampano Foo.M Come puoi vedere, questo approccio ti consente di avere una nuova implementazione per un metodo purché il riferimento a quell’object sia del tipo corretto derivato, ma nascondendo un metodo di base si rompe il polimorfismo.

Ti consigliamo di non hide i metodi di base in questo modo.

Tendo a schierarmi con coloro che preferiscono il comportamento predefinito di C # che i metodi non sono virtuali per impostazione predefinita (al contrario di Java). Vorrei andare ancora oltre e dire che le classi dovrebbero anche essere sigillate di default. L’ereditarietà è difficile da progettare correttamente e il fatto che esista un metodo che non è contrassegnato per essere virtuale indica che l’autore di quel metodo non ha mai avuto intenzione di sovrascrivere il metodo.

Modifica: “invio polimorfico del tempo di esecuzione” :

Ciò che intendo è il comportamento predefinito che si verifica al momento dell’esecuzione quando si chiamano metodi virtuali. Diciamo per esempio che nel mio precedente esempio di codice, piuttosto che definire un metodo non virtuale, ho effettivamente definito un metodo virtuale e un metodo vero e proprio sovrascritto.

Se dovessi chiamare b.Foo in tal caso, il CLR determinerebbe correttamente il tipo di object che il riferimento b indica come Bar e invierà la chiamata a M appropriato.

No, non puoi.

È ansible ignorare solo un metodo virtuale: vedere il MSDN qui :

In C #, le classi derivate possono contenere metodi con lo stesso nome dei metodi della class base.

  • Il metodo della class base deve essere definito virtuale.

Se la class base non è sigillata, puoi ereditarla e scrivere un nuovo metodo che nasconde quello di base (usa la “nuova” parola chiave nella dichiarazione del metodo). Altrimenti no, non puoi sovrascriverlo perché non è mai stato scavalcato l’autore originale, quindi perché non è virtuale.

Penso che ti stia sovraccaricando e sovrascruisci confuso, sovraccarico significa che hai due o più metodi con lo stesso nome ma diversi set di parametri mentre esegui l’override significa che hai un’implementazione diversa per un metodo in una class derivata (sostituendo o modificando in tal modo il comportamento nella sua class base).

Se un metodo è virtuale, è ansible sovrascriverlo utilizzando la parola chiave override nella class derrived. Tuttavia, i metodi non virtuali possono solo hide l’implementazione di base utilizzando la nuova parola chiave al posto della parola chiave override. La route non virtuale è inutile se il chiamante accede al metodo tramite una variabile digitata come tipo base, in quanto il compilatore utilizza un invio statico al metodo base (ovvero il codice nella class derrived non verrà mai chiamato).

Non c’è mai nulla che ti impedisca di aggiungere un sovraccarico a una class esistente, ma solo il codice che conosce la tua class sarebbe in grado di accedervi.

Nel caso in cui tu stia ereditando da una class non derivata, potresti semplicemente creare una super class astratta e ereditarla invece a valle.

C’è un modo per sovrascrivere un metodo non virtuale? o qualcosa che dia risultati simili (oltre a creare un nuovo metodo per chiamare il metodo desiderato)?

Non è ansible sovrascrivere un metodo non virtuale. Tuttavia puoi utilizzare la new parola chiave modificatore per ottenere risultati simili:

 class Class0 { public int Test() { return 0; } } class Class1 : Class0 { public new int Test() { return 1; } } . . . // result of 1 Console.WriteLine(new Class1().Test()); 

Dovrai anche assicurarti che il modificatore di accesso sia lo stesso, altrimenti non otterrai l’ereditarietà della linea. Se un’altra class eredita da Class1 la new parola chiave in Class1 non influirà sugli oggetti che ne ereditano, a meno che il modificatore di accesso non sia lo stesso.

Se il modificatore di accesso non è lo stesso:

 class Class0 { protected int Test() { return 0; } } class Class1 : Class0 { // different access modifier new int Test() { return 1; } } class Class2 : Class1 { public int Result() { return Test(); } } . . . // result of 0 Console.WriteLine(new Class2().Result()); 

… contro se il modificatore di accesso è lo stesso:

 class Class0 { protected int Test() { return 0; } } class Class1 : Class0 { // same access modifier protected new int Test() { return 1; } } class Class2 : Class1 { public int Result() { return Test(); } } . . . // result of 1 Console.WriteLine(new Class2().Result()); 

Come sottolineato in una risposta precedente, questo non è un buon principio di progettazione.

C’è un modo per ottenerlo usando un metodo astratto di class e astratto.

Prendere in considerazione

 Class Base { void MethodToBeTested() { ... } void Method1() { } void Method2() { } ... } 

Ora, se si desidera avere diverse versioni del metodo MethodToBeTested (), quindi modificare Class Base in una class astratta e il metodo MethodToBeTested () come metodo astratto

 abstract Class Base { abstract void MethodToBeTested(); void Method1() { } void Method2() { } ... } 

Con il metodo abstract MethodToBeTested () arriva un problema; l’implementazione è andata.

Quindi creare una class DefaultBaseImplementation : Base per avere l’implementazione predefinita.

E crea un’altra class UnitTestImplementation : Base per implementare il test dell’unità.

Con queste 2 nuove classi, la funzionalità della class base può essere sovrascritta.

 Class DefaultBaseImplementation : Base { override void MethodToBeTested() { //Base (default) implementation goes here } } Class UnitTestImplementation : Base { override void MethodToBeTested() { //Unit test implementation goes here } } 

Ora avete 2 classi che implementano (override) MethodToBeTested() .

È ansible creare un’istanza della class (derivata) come richiesto (ovvero con l’implementazione di base o con l’implementazione del test di unità).