views:

255

answers:

3

I want to have some function that would return "Base" if a variable of class Base was passed to it, "Derived" if it was declared as Derived, etc. Not depending on runtime type of a value it was assigned to.

+2  A: 

Just recurse on GetType() until you hit object.

emptyset
Yes, I did this, it worked but slowly.
Misha
+3  A: 

This is not possible without parsing the code in question.

At runtime only two pieces of type information are available, the actual type of a value (via object.GetType()) and, if the variable in question is a parameter or class/instance variable the FieldType property on a FieldInfo, PropertyType on a PropertyInfo or ParameterType on a ParameterInfo.

Since the value passed to you may well have come via several variables on its route to you the question is not even well defined I'm afraid.

Ah - I see you want only the type as currently defined in the method, the Expression functionality will provide this (Roman's answer shows a neat way to do this) but beware trying to use this outside the method... In essence you are letting the generic type inference of the compiler infer the type in question but this means that the variable used is not always the variable you can see. It may instead be that of a compiler synthesised variable, for example:

string x = "x";
Console.WriteLine(x.GetDeclaredType()); // string
Console.WriteLine(((object)x).GetDeclaredType()); // object

Since the compiler synthesises a temporary variable in which to place an object reference to x.

ShuggyCoUk
+1, btw, actual is referred to as "concrete" type...
Charles Bretana
I wasn't interested in a value, only name of type the variable was declared with... Thanks anyway, useful info.
Misha
+1 for your warnings
Roman Boiko
Thanks a lot, especially with for warnings.
Misha
+13  A: 

See code below for example. The key is to use Generics, extension method was used just for nice syntax.

using System;

static class Program
{
    public static Type GetDeclaredType<T>(this T obj)
    {
        return typeof(T);
    }

    // Demonstrate how GetDeclaredType works
    static void Main(string[] args)
    {
        ICollection iCollection = new List<string>();
        IEnumerable iEnumerable = new List<string>();
        IList<string> iList = new List<string>();
        List<string> list = null;

        Type[] types = new Type[]{
            iCollection.GetDeclaredType(),
            iEnumerable.GetDeclaredType(),
            iList.GetDeclaredType(),
            list.GetDeclaredType()
        };

        foreach (Type t in types)
            Console.WriteLine(t.Name);
    }
}

Result:

ICollection
IEnumerable
IList`1
List`1

EDIT: You may also avoid using extension method here, as it would cause it to appear on every IntelliSense drop-down list. See another example:

using System;
using System.Collections;

static class Program
{
    public static Type GetDeclaredType<T>(T obj)
    {
        return typeof(T);
    }

    static void Main(string[] args)
    {
        ICollection iCollection = new List<string>();
        IEnumerable iEnumerable = new List<string>();

        Type[] types = new Type[]{
                GetDeclaredType(iCollection),
                GetDeclaredType(iEnumerable)
        };

        foreach (Type t in types)
            Console.WriteLine(t.Name);
    }
}

also produces correct results.

Roman Boiko
+1. Smooth! (filling up for the 15 char limit)
Heinzi
wow! thanks a lot!!!
Misha
I was in a similar situation, so luckily just needed to find my sample code :)
Roman Boiko
I'll use 2nd solution (from your edit), thank you
Misha
Nice code, but I would think that the key is to use **reflection**, generics is just a part of your solution to the problem. Without reflection, there is no way to determine type at runtime.
Sune Rievers
@Sune: Type was determined at compile time. This is not type of instance, but declared type of variable. It is static, not dynamic.Only instance (of class System.Type) is created at runtime. I guess, this is what you meant.
Roman Boiko
Similar example: if one would write `string s = "blah";`, the `"blah"` value would be defined at compile time, but instance of class `String` with this value would be created at runtime. (All objects are created at runtime.)
Roman Boiko
Thus there is no reflection involved. `typeof(T)` operator doesn't use reflection.
Roman Boiko