1

The code below is a simplification to show what's happening. When declaring b1 specifically as the base type, t1 is Base type and t2 is Derived type. When b2 is declared with var, both t1 and t2 are Derived type. So this means that the generic code generated for handling b1 works with the base type. Is this by design, and why? And is there a way around it, so with b1, t1 and t2 are both Derived type (without changing to var)?

class Base { }
class Derived : Base { }
class Program
{
    static void Main()
    {
        Base b1 = new Derived();
        var b2 = new Derived();
        SomeMethod(b1);
        SomeMethod(b2);

    }
    private static void SomeMethod<T>(T obj) where T : Base
    {
        var t1 = typeof(T);
        var t2 = obj.GetType();
    }
}
Paw Baltzersen
  • 2,662
  • 3
  • 24
  • 33
  • 1
    If `b1` is declared as `Base`, the compiler has to assume when it calls `SomeMethod` that it's calling `SomeMethod`. It can't make the assumption that `b1` is `Derived` because it might not be – Matt Burland Apr 25 '17 at 19:19
  • 1
    That's what we call *Run time polymprphism* – Rahul Apr 25 '17 at 19:19
  • This is all described in the documentation for `typeof` and `GetType()`. The former is the _compile-time_ type, i.e. the type known by the compiler. You passed an object statically declared as `Base`, so that's all the method knows (see second marked duplicate, regarding type parameter inference). But the _run-time_ type is of course whatever the object really is. It is no different than if you had a non-generic method declared as `void SomeMethod(Base obj)` and checked `typeof(Base)`. – Peter Duniho Apr 25 '17 at 22:47
  • See also https://stackoverflow.com/questions/28379570/best-way-to-get-runtime-type-of-t, https://stackoverflow.com/questions/2004508/checking-type-parameter-of-a-generic-method-in-c-sharp, and https://stackoverflow.com/questions/14985681/how-does-a-generic-method-work for closely related posts that you should have found while searching Stack Overflow for the answer to your question before you posted it. – Peter Duniho Apr 25 '17 at 22:47
  • _" is there a way around it, so with b1, t1 and t2 are both Derived type"_ -- if you want "a way around it", then you're using generics wrong. If your code had just been academic, for the point of discussion, that would be one thing. But if you really have a generic method that not only checks `typeof(T)`, but in fact relies on that returning the same type as `GetType()` on an object of type `T` passed to the method, then you're doing it wrong. Your generic method shouldn't have to check the type at all; that's the whole point of generics! – Peter Duniho Apr 25 '17 at 22:54
  • @PeterDuniho I did look through the suggested questions but they weren't even close to this. – Paw Baltzersen Apr 26 '17 at 06:51

2 Answers2

0

You should better make an interface and let the Base inhert from it. And the you could do something like this

private static void SomeMethod<T>(T obj) where T : IBase
    {
        var t1 = typeof(T);
        var t2 = obj.GetType();
    }

Now T can be anything that have inherted from IBase

Alen.Toma
  • 4,684
  • 2
  • 14
  • 31
0

The type parameter T is inferred at compile time, that's why it's different when you call a method with a parameter Base b1 and Derived b2 (using var simply makes the type of the variable the same as the type of the expression used to initialize it).

The simplest way to make it happen at run time is to cast the parameter to dynamic

SomeMethod((dynamic)b1);

This will basically run the compiler at run time and perform overload resolution and type inference with run time types instead of compile time types.

In general what you're asking about is called double dispatch - choosing the method to call based on both the runtime type of the object whose method you call, and the run time type of the parameter. A traditional way to achieve it is to use the visitor pattern.

Jakub Lortz
  • 14,616
  • 3
  • 25
  • 39