The new keyword only works properly when dealing with the derived
class directly. Whenever the base class is used (the general case) the base
class implementation will still be used. For example imagine this class layout.
public class BaseClass
{
public string Foo ( ) { return "BaseClass"; }
}
public class DerivedClass : BaseClass
{
public new string Foo ( ) { return "DerivedClass"; }
}
Now imagine that in the application code the following method is written.
public void CallFoo ( BaseClass cls )
{ Console.WriteLine(cls.Foo()); }
If a BaseClass instance is passed to the method it will print out "BaseClass". Logically you would expect that if you were to pass a DerivedClass instance
that the compiler would realize that you overrode the base class through the
new modifier. However the compiler is not responsible for determining
who to call at runtime. That falls to the CLR. Instead the compiler,
at compile time, determines that a method might have differing implementations (because
it is virtual). The compiler generates the necessary code to look up the appropriate
method at runtime. However since Foo is not virtual the compiler
will generate a direct call to BaseClass.Foo whenever it sees it in the
code.
When the compiler sees DerivedClass.Foo it realizes that the method has
been overridden even though it is not virtual and therefore will invoke the correct
method at runtime. However this only works when the compiler knows it is dealing
with DerivedClass. Hence the new modifier gives
us a false sense of virtuality and should be avoided in most cases.