Luca Trazzi
Luca Trazzi

Reputation: 1260

Generic Method issue/bug?

Can anyone explain me this issue?

the only way to get this working, is to use the virtual in the CorrectName and then override in the Derived one, instead of new keyword, but, WHY is this happening?

WHY if I cast by generic it gives me the Base value, and if I cast it directly it gives me Derived value? ((Output is below))

Thanks guys, as I've said you, I already got the "solution", but I want to UNDERSTAND

    class Base
    {
        public string Name { get; set; }
        public string CorrectName { get { return Name; } }
    }
    class Derived : Base
    {
        public new string CorrectName { get { return "NEW" + Name; } }
    }
    static void Main(string[] args)
    {
        List<Derived> container = new List<Derived>();

        var d = new Derived() { Name = "NameDerived2" };

        container.Add(d);

        Search<Derived>(container);
        Console.ReadLine();
    }

    static void Search<T>(List<T> list) where T : Base
    {
        foreach (var el in list)
        {
            Console.WriteLine("No Cast -->" + el.CorrectName);
            Console.WriteLine("Generic Cast -->" + (el as T).CorrectName);
            Console.WriteLine("Direct Cast -->" + (el as Derived).CorrectName);
        }
    }

OUTPUT:

No Cast -->NameDerived2

Generic Cast -->NameDerived2

Direct Cast -->NEWNameDerived2

TABLE OF TRUTH:

el is Derived == true
el.GetType().Equals(typeof(Derived)) == true
el.GetType().Equals(typeof(T)) == true
el.GetType().Equals(typeof(Base)) == false
typeof(T).Equals(typeof(Base)) == false
typeof(T).Equals(typeof(Derived)) == true

Upvotes: 5

Views: 172

Answers (2)

jam40jeff
jam40jeff

Reputation: 2596

Non-virtual methods are bound at compile-time, not run-time. At compile-time, all that can be guaranteed is that T is a Base, so the compiler binds the property accessor to the Base version of CorrectName and this will not change at run-time. You are calling the method with Derived as the type parameter T, but others could call it with another type inheriting from Base, or even Base itself.

Virtual methods, however, will inspect the actual runtime type and call the correct overridden method.

The "table of truth" you posted is irrelevant here, since all of those are evaluated at runtime. To prove that the compiler evaluates T as if it were Base, try the following:

T t = default(T);
object o = t; // works
Base b = t; // works
Derived d = t; // doesn't work

Upvotes: 0

Thorsten Dittmar
Thorsten Dittmar

Reputation: 56697

Without the virtual keyword, the method in the base class is not overridden, but "hidden" by the new implementation. You're also enforcing this by using the new keyword in Derived. As you said in your generic method declaration, any T passed to the method must be of type Base, so every T is cast to Base.

What happens now is that when you don't use virtual, you lose polymorphism, that means, even though the object is actually of type Derived, but cast to Base, the Base implementation of CorrectName is called, not - as you'd expect - the new implementation in Derived.

This is only called when you explicitly cast your object to Derived.

This has also been discussed and described here: virtual keyword in c#

Another link that might help you understand the difference between virtual and non-virtual methods could be this: http://en.wikipedia.org/wiki/Virtual_method_table

Upvotes: 4

Related Questions