C#: uno strano comportamento con l'override

Per una buona comprensione di questo post è necessario conoscere l'ereditarietà a livello elementare e cosa sono i params.

Ieri mi sono trovato all'improvviso in un loop infinito. Per quanto potesse essere chiaro cosa stava succedendo, non mi è stato subito chiaro il PERCHE'.

Oggi ho scritto un po' di codice in modo da mettere la situazione su un "banco di prova".

La necessità era quella di ampliare una classe di log in modo da incorporare una funzionalità inn stile string.format.

   1:          public class clsLogger
   2:          {
   3:              public void scrivi(string Msg)
   4:              {
   5:                  Console.WriteLine("1)" + Msg);
   6:              }
   7:              public void scrivi(string Msg, params object[] arg)
   8:              {
   9:                  scrivi("2)" + string.Format(Msg, arg));
  10:              }
  11:          }
  12:   
  13:   
  14:          static void Main(string[] args)
  15:          {
  16:              Console.WriteLine("********* Test Overload ***********");
  17:   
  18:              clsLogger Test = new clsLogger();
  19:              Test.scrivi("Scrivi");
  20:              Test.scrivi("Scrivi, parametro: {0}", 123456);
  21:   
  22:              Console.ReadKey();
  23:          }

In questo modo il compilatore è perfettamente in grado di distinguere i due metodi: la chiamata scrivi della riga 19 si riferisce al metodo scrivi della riga 3 mentre la chiamata della riga 20 alla funzione scrivi della riga 7.

Complichiamoci un poco la situazione: la nostra classe di log deve estenderne una di base in cui è definito il metodo scrivi semplice.

   1:          public class clsLoggerBase
   2:          {
   3:              public virtual void scrivi(string Msg)
   4:              {
   5:                  Console.WriteLine("1)" + Msg);
   6:              }
   7:          }
   8:   
   9:          public class clsLoggerInherits : clsLoggerBase
  10:          {
  11:              public override void scrivi(string Msg)
  12:              {
  13:                  base.scrivi(Msg);
  14:              }
  15:              public void scrivi(string Msg, params object[] arg)
  16:              {
  17:                  scrivi("2)" + string.Format(Msg, arg));
  18:              }
  19:          }
  20:   
  21:          static void Main(string[] args)
  22:          {
  23:              Console.WriteLine("********* Test Overload ***********");
  24:   
  25:              clsLoggerInherits Test = new clsLoggerInherits();
  26:              Test.scrivi("Scrivi");
  27:              Test.scrivi("Scrivi, parametro: {0}", 123456);
  28:   
  29:              Console.ReadKey();
  30:          }

In questo caso il compilatore referenzia sempre il metodo della riga 15. Questo avviene sia nelle due chiamate alle righe 26 e 27 della funzione Main, sia nella chiamate interna di riga 17 (che diventa ricorsiva generando un'eccezione di stackoverflow).

Anche non sovrascrivendo la funzione scrivi in clsLoggerInherits otteniamo la stessa situazione.

«novembre»
domlunmarmergiovensab
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456