Partendo da  questo post di
 Marco Russo e indagando un po' sulla modifica di
accessibilità nella sovrascrittura di un metodo virtuale in una relazione di
ereditarietà, ho scoperto che, ai metodi Foo in questo codice C++:
#using <mscorlib.dll>
using namespace
System;
public __gc
class A
{
 
protected: virtual
void Foo()
  {
    Console::WriteLine(S"A");
  }
};
public __gc
class B: public
A
{
 
protected: virtual
void Foo()
  {
    Console::WriteLine(S"B");
  }
};
public __gc
class C: public
B
{
 
public: virtual
void Foo()
  {
    Console::WriteLine(S"C");
  }
};
corrispondono le seguenti signature IL:
.method family  newslot virtual instance void Foo()
 cil managed //
A
.method family virtual instance void  Foo()  cil managed //
B
.method public virtual instance void  Foo()  cil managed //
C
dove si nota in rosso il flag newslot
solo sul metodo della classe base. Il flag newslot in IL
"corrisponde" al modificatore new in C# e al modificatore Shadows
in VB .NET ("corrisponde" non è, forse, la parola giusta...). Siamo
abituati a pensare a questo modificatore in situazioni di "hiding an
inherited member" (10.7.1.2, ECMA-334) e perciò si trova (di solito)
in classi derivate e non in classi base. Però, nell'esempio sopra, il
compilatore C++ l'ha inserito nella classe base!
In C# non è possibile questa modifica di accessibilità. Il seguente codice
C# non compila (vedi l'errore CS0507):
using System;
public class
A
{
 
protected virtual
void Foo()
  {
    Console.WriteLine("A");
  }
}
public class
B: A
{
 
protected override
void Foo()
  {
    Console.WriteLine("B");
  }
}
public class
C: B
{
 
// error CS0507: 'C.Foo()':
  // cannot change access modifiers when
  // overriding 'protected' inherited
member 'B.Foo()'
 
public override
void Foo()
  {
    Console.WriteLine("C");
  }
}
Impostando però come  new virtual il metodo
 Foo della classe C:
using System;
public class
A
{
 
protected virtual
void Foo()
  {
    Console.WriteLine("A");
  }
}
public class
B: A
{
 
protected override
void Foo()
  {
    Console.WriteLine("B");
  }
}
public class
C: B
{
 
public new virtual void Foo()
  {
    Console.WriteLine("C");
  }
}
lo snippet compila e otteniamo queste signature IL:
.method family hidebysig newslot virtual instance void Foo()
 cil managed //
A
.method family hidebysig virtual instance void  Foo()  cil managed //
B
.method public hidebysig  newslot  virtual instance void  Foo()  cil managed //
C
Ma se per il metodo Foo della classe B avessimo avuto virtual
al posto di override?
using System;
public class
A
{
 
protected virtual
void Foo()
  {
    Console.WriteLine("A");
  }
}
public class
B: A
{
 
protected virtual void Foo()
  {
    Console.WriteLine("B");
  }
}
public class
C: B
{
 
public new virtual void Foo()
  {
    Console.WriteLine("C");
  }
}
In questo caso, il compilatore C# avrebbe inserito il flag newslot nella
signature di tutti e tre i metodi:
.method family hidebysig newslot virtual instance void Foo()
 cil managed //
A
.method family hidebysig newslot virtual instance void  Foo()  cil managed //
B
.method public hidebysig  newslot  virtual instance void  Foo()  cil managed //
C
Proprio come diceva (chi altro?) Anders Hejlsberg in questa
intervista:
"When you say "virtual," you can mean one of two things. If you did not inherit a method of the same signature, then this is a new virtual method. That's one meaning. Otherwise it is an override of an inherited method. That's the other meaning."
  "In C#, you must explicitly indicate which meaning of virtual you intend. To declare a new virtual method, you just mark it
  
  virtual. But to override an existing virtual method, you must say
   override."
Avete notato? "If you did not inherit a method of the same signature, then this is a
 new  virtual method." e
"To declare a  new virtual method, you just mark it
  virtual". Cioè, un nuovo metodo virtuale significa un nuovo slot
(newslot), ovvero un nuovo elemento, nella v-table! Ecco perché ha senso
incontrare newslot in una classe base (lo snippet C++ da cui siamo
partiti). newslot non corrisponde al modificatore new ma,
lo implementa.
Ottima scelta il nome del flag in IL, newslot, non altrettanto ottima,
a mio parere, la scelta del nome del modificatore in C#/VB .NET: new/Shadows.