The call to method F() from your inherited class object prints B.F for the object of type D downcasted to type A, because you override the method in class B (and class D).
Your test is an almost exact copy of the example provided in this MSDN post on virtual methods:
using System;
class A
{
public void F() { Console.WriteLine("A.F"); }
public virtual void G() { Console.WriteLine("A.G"); }
}
class B: A
{
new public void F() { Console.WriteLine("B.F"); }
public override void G() { Console.WriteLine("B.G"); }
}
class Test
{
static void Main() {
B b = new B();
A a = b;
a.F();
b.F();
a.G();
b.G();
}
}
In the example, A introduces a non-virtual method F and a virtual
method G. The class B introduces a new non-virtual method F, thus
hiding the inherited F, and also overrides the inherited method G. The
example produces the output:
A.F
B.F
B.G
B.G
Notice that the statement
a.G() invokes B.G, not A.G. This is because the run-time type of the
instance (which is B), not the compile-time type of the instance
(which is A), determines the actual method implementation to invoke.
Because methods are allowed to hide inherited methods, it is possible
for a class to contain several virtual methods with the same
signature. This does not present an ambiguity problem, since all but
the most derived method are hidden. In the example