tags:

views:

77

answers:

6

Cannot explain what is going on the following program. GetType is returning the type I want to return and not the original one. Does that mean we cannot rely on GetType? is operator is right though. Can anybody please explain it in detail?

using System;

namespace ConsoleApplication2
{
    public class MyClass
    {
        public Type GetType()
        {
            return typeof(Program);
        }

    }

class Program
{
    static void Main(string[] args)
    {
        MyClass mc = new MyClass();

        if (mc.GetType() == typeof(Program))
        {
            Console.WriteLine("Confused."); 
        }
        if(mc is Program)
        {
            Console.WriteLine(mc.GetType()); // Don't get inside the if. Why?
        }

    }
}
}

Update: I am reading the book CLR via C# 3rd edition. In chapter 4 (2nd page) when it explains different methods in System.Object it says

"The GetType method is nonvirtual, which prevents a class overriding this method and lying about its type"

While I agree about the first statement, I am lying about MyClass type. ain't I?

A: 

It will only be true if:

if (mc is MyClass) { ... }
Ruel
A: 

According to the documentation, the 'is' operator is not overloadable. That is why it is probably not getting into your second 'if' statement.

Check out this page from MSDN: http://msdn.microsoft.com/en-us/library/8edha89s%28v=VS.80%29.aspx

Wim Haanstra
+1  A: 

is checks the actual runtime type of your variable. The compiler don't care that you have defined a method called GetType() that returns another Type. It still knows that the actuall type of your variable is MyClass.

What exactly are you trying to accomplish here? Why do you need your MyClass class to impersonate the Program class?

Øyvind Bråthen
+2  A: 

Object.GetType is not a virtual method. So mc is MyClass and effectively calls Object.GetType and not your method.

ars
How does it (is operator) do it? Does it first cast mc to object first and then calls the GetType method? Also please see the update of my question. Does it men while we can depend on 'is' we cant on GetType directly.
Tanmoy
I believe the `is` operator boils down to the `isinst` instruction in the CLR. I don't know how this is implemented, but it probably consults the object's table similar to GetType. The result is the same as testing with `((object)mc).GetType()`.
ars
+3  A: 

Please take care of the warning, as they do exists for reasons. Your code compiled with the following warning:

Warning 1 'ConsoleApplication2.MyClass.GetType()' hides inherited member 'object.GetType()'. Use the new keyword if hiding was intended.

which means GetType() is non-virtual and you are writing new unrelated method of GetType() that CLR will never call it.

tia
I am sorry if my question did not made it clear. Its about academic/theoretical interest rather than writing production code with best practices.
Tanmoy
+3  A: 

is operator implemented in terms of as operator and finally use isinst IL instruction. And of course this instruction don't know about your not virtual GetType method that you define in some class in your inheritance hierarchy.

To understand this "confusing" behavior lets "implement" our own version of the "is operator":

public class MyClass
{
    public Type GetType()
    {
        return typeof(Program);
    }

}

class Program {

    //this is oversimplified implementation,
    //but I want to show the main differences
    public static bool IsInstOf(object o, Type t)
    {
        //calling GetType on System.Object
        return o.GetType().IsAssignableFrom(t);
    }

    static void Main(string[] args)
    {
        MyClass mc = new MyClass();

        //calling MyClass non-virtual version for GetType method
        if (mc.GetType() == typeof(Program))
        {
            //Yep, this condition is true
            Console.WriteLine("Not surprised!");
        }

        //Calling System.Object non-virtual version for GetType method
        if (IsInstOf(mc, typeof(Program)))
        {
            //Nope, this condition isn't met!
            //because mc.GetType() != ((object)mc).GetType()!
        }

        Console.ReadLine();
    }            
}
Sergey Teplyakov