When the method is declared as virtual
the resolution of the method that will be called is deferred until runtime and depends on the type of the object at runtime. From the C# spec:
In a virtual method invocation, the run-time type of the instance for
which that invocation takes place determines the actual method
implementation to invoke.
From the C# spec, the resolution of a virtual method is as follows:
For every virtual method declared in or inherited by a class, there
exists a most derived implementation of the method with respect to
that class. The most derived implementation of a virtual method M with
respect to a class R is determined as follows:
- If R contains the introducing virtual declaration of M, then this is the most derived implementation of M.
- Otherwise, if R contains an override of M, then this is the most derived implementation of M.
- Otherwise, the most derived implementation of M with respect to R is the same as the most derived implementation of M with respect to
the direct base class of R.
So when you write:
T h2 = (T)this;
h2.write();
The compiler knows h2 is of type hello
or derived, and that write
is a virtual method whose resolution will be deferred until runtime.
At runtime, the resolution will chose the method in class hello
even though the class is of type hello2
. This is because the write
method in class hello2
does not contains the override
keyword and won't be considered when resolving the virtual call. (So the only way to call write on hello2
is by making sure the compiler knows the instance is of type hello2
)
This is also why if you declare write on hello2
with override instead of new the output of the same program would be hello2 in both cases.
Edit
It seems you want to write a method that is able to call write
in hello
or hello2
even though the method has been declared with the new operator in hello2
.
You could write a extension method that uses a dynamic
variable. For example create the following extension method:
public static class HelloExtensions
{
public static void writeDynamic<T>(this T h) where T: hello
{
dynamic hdynamic = h;
hdynamic.write();
}
}
Then you could write the following test program that uses that extension method with your original classes:
class Program
{
static void Main(string[] args)
{
testDynamic(new hello());
testDynamic(new hello2());
Console.ReadLine();
}
static void testDynamic(hello h)
{
h.writeDynamic();
}
}
The output will be:
hello
hello2