111

In a non-static method I could use this.GetType() and it would return the Type. How can I get the same Type in a static method? Of course, I can't just write typeof(ThisTypeName) because ThisTypeName is known only in runtime. Thanks!

Yegor
  • 2,514
  • 2
  • 19
  • 27
  • 16
    You are in a STATIC context and cannot write typeof(ThisTypeName)? How? – Bruno Reis Jan 17 '10 at 16:15
  • 1
    There is nothing like 'runtime' inside a static method ( assuming you are not talking about an argument that is passed to a static method). In that case you can simply say typeof(RelevantType) . – Manish Basantani Jan 17 '10 at 16:27
  • 2
    A static method cannot be virtual. You already know the type. – Hans Passant Jan 17 '10 at 16:48
  • 7
    There will be many derived classes from an abstract one. The base abstract class has static dictionary. So derived classes “register” itself in static constructors (dic.Add(N, T)). And yes, I do know the type :) I'm just a bit lazy and don't like to replace the text and was wondering if “T” can be determined in runtime. Please excuse my lie, because it was needed to just simplify the question. And it worked ;) There is an accepted solution now. Thanks. – Yegor Jan 17 '10 at 17:21
  • A subclass inherits static methods of its superclass, no? Wouldn't it make sense for a superclass static method to be useful for all of its sub-classes? Static simply means without an instance, surely the principle of common code in a common base class applies to static methods as well as instance methods? – Matt Connolly Aug 18 '11 at 23:50
  • Here's a different approach, that relies on looking at a stacktrace to allow the baseclass static method to see the type of the caller: http://stackoverflow.com/questions/3064227/get-derived-class-type-from-a-bases-class-static-method/17911395#17911395 – Χpẘ Jul 28 '13 at 18:33
  • @BrunoReis, He's probably in a static context in the current method... but probably not a frame or two up the callstack. But here's one real scenario. WPF. You have a control bound to a static property on a non-static class object in your DataContext. Now in the 'get' of your static property, you're "technically" in a static context, but you as the programmer know there's a REAL non-static object which might be inherited from your base class with the static property... Of course, the answer here is probably to not use a static property... but you see the point. – C. Tewalt Feb 14 '16 at 06:31
  • I stumbled upon this being in the same situation. Consider: `List typesOfA; abstract class A { static RegisterA { typesOfA.Add(THISTYPE); } }`. – mireazma Nov 17 '20 at 16:50

8 Answers8

153

If you're looking for a 1 liner that is equivalent to this.GetType() for static methods, try the following.

Type t = MethodBase.GetCurrentMethod().DeclaringType

Although this is likely much more expensive than just using typeof(TheTypeName).

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    This one works fine. Thanks :) It's not that expensive because it'll be called quite rare. – Yegor Jan 17 '10 at 17:11
  • 2
    Entrase, by "expensive" Jared means that they are costly for the processor, usually meaning slow. But he said, "much more expensive" meaning slower. Probably not slow at all, unless you are designing a rocket-guidance system. – Dan Rosenstark Jan 17 '10 at 17:32
  • 1
    I've seen GetCurrentMethod cause some serious performance problems. But since you are just getting the type you can cache it. – Jonathan Allen May 26 '10 at 03:43
  • 64
    This always returns the class that implements the current method, not the class it was called on in the case of subclasses. – Matt Connolly Aug 18 '11 at 23:51
  • 3
    I guess It's handy to avoid errors if code ever gets migrated to different class names or something, but a good refactoring tool should take care of the `typeof(TheTypeName)` anyway. – Nyerguds Jul 02 '15 at 09:44
59

There's something that the other answers haven't quite clarified, and which is relevant to your idea of the type only being available at execution time.

If you use a derived type to execute a static member, the real type name is omitted in the binary. So for example, compile this code:

UnicodeEncoding.GetEncoding(0);

Now use ildasm on it... you'll see that the call is emitted like this:

IL_0002:  call       class [mscorlib]System.Text.Encoding 
[mscorlib]System.Text.Encoding::GetEncoding(int32)

The compiler has resolved the call to Encoding.GetEncoding - there's no trace of UnicodeEncoding left. That makes your idea of "the current type" nonsensical, I'm afraid.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Fast forward 10 years and why aren't there still virtual statics in C#? ;) usually one wouldn't need them... but there are rare occasions when they'd come in handy ;) – marchewek Sep 12 '20 at 19:48
  • 1
    @marchewek: Very, very rare I'd say - rare enough that the C# team has always found more useful things to do. (It's not like they've been idle this whole time...) – Jon Skeet Sep 12 '20 at 21:11
  • 1
    I do think it because C# is lacking of features for static classes in general. You cannot override static method. You cannot have static methods or constructors in interface. Part of can be replaced by reflection. Example case is de/serialization. With such feature as static methods in interface you can implement it without reflection. Obtaining type of class from static method is useful for moving shared initialization code of singleton into the base class. This is the case of "I don't know I was needed it", I do think. All those approaches are used in Objective-C/Swift. – Krypt Jan 21 '21 at 10:28
  • 1
    Static abstracts in interfaces are likely coming in C# 11 ([source 1](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-08-30.md), [source 2](https://github.com/dotnet/csharplang/issues/4436)) – JamieGL Nov 29 '21 at 14:51
28

Another solution is to use a selfreferecing type

//My base class
//I add a type to my base class use that in the 
//static method to check the type of the caller.
public class Parent<TSelfReferenceType>
{
    public static Type GetType()
    {
        return typeof(TSelfReferenceType);
    }
}

Then in the class that inherits it, I make a self referencing type:

public class Child: Parent<Child>
{
}

Now the call type typeof(TSelfReferenceType) inside Parent will get and return the Type of the caller without the need of an instance.

Child.GetType();
Metro Smurf
  • 37,266
  • 20
  • 108
  • 140
Rob Leclerc
  • 898
  • 9
  • 11
  • I've used this for singleton patterns, i.e. Singleton ... static members can then refer to typeof(T) in error messages or wherever else it's needed. – yoyo Dec 07 '11 at 22:03
  • 2
    Hi. I really like and appreciate this answer because it give me a work-around to find the child type from a static base function. – Bill Software Engineer Jul 24 '12 at 17:29
  • 1
    Nice one. Too sad that in C# this cannot be done without this little code duplication, though. – Display Name Sep 02 '13 at 10:46
  • There is another example of this workaround on http://stackoverflow.com/a/22532416/448568 – Steven de Salas Jan 09 '15 at 01:08
  • 2
    Both (this one and the one linked by Steven) will not work for the inheritors of an implementer of the base class... Grandchildren will end up with Child type... Too bad C# doesn't have virtual statics ;) – marchewek Sep 12 '20 at 19:41
  • 1
    Don't... see: https://ericlippert.com/2011/02/02/curiouser-and-curiouser/ and even if you don't care. You should just use use typeof(Child) directly. – Wouter Apr 12 '22 at 20:25
5

You can't use this in a static method, so that's not possible directly. However, if you need the type of some object, just call GetType on it and make the this instance a parameter that you have to pass, e.g.:

public class Car {
  public static void Drive(Car c) {
    Console.WriteLine("Driving a {0}", c.GetType());
  }
}

This seems like a poor design, though. Are you sure that you really need to get the type of the instance itself inside of its own static method? That seems a little bizarre. Why not just use an instance method?

public class Car {
  public void Drive() { // Remove parameter; doesn't need to be static.
    Console.WriteLine("Driving a {0}", this.GetType());
  }
}
John Feminella
  • 303,634
  • 46
  • 339
  • 357
3

I don't understand why you cannot use typeof(ThisTypeName). If this is a non-generic type, then this should work:

class Foo {
   static void Method1 () {
      Type t = typeof (Foo); // Can just hard code this
   }
}

If it's a generic type, then:

class Foo<T> {
    static void Method1 () {
       Type t = typeof (Foo<T>);
    }
}

Am I missing something obvious here?

Tarydon
  • 5,097
  • 23
  • 24
  • 8
    This won't work if you create a class Bar derived from Foo and then the class inherits Method1 - then a call to Bar.Method1 will still process typeof(Foo) which is wrong. The inherited Method1 should somehow know that it is dervied in Bar, and then get the typeof(Bar). – JustAMartin May 09 '13 at 12:35
0

EDIT This methods will works only when you deploy PDB files with the executable/library, as markmnl pointed out to me.

Otherwise will be a huge issue to be detected: works well in developement, but maybe not in production.


Utility method, simply call the method when you need, from every place of your code:

public static Type GetType()
{
    var stack = new System.Diagnostics.StackTrace();

    if (stack.FrameCount < 2)
        return null;

    return (stack.GetFrame(1).GetMethod() as System.Reflection.MethodInfo).DeclaringType;
}
Community
  • 1
  • 1
T-moty
  • 2,679
  • 1
  • 26
  • 31
  • 1
    StackTrace is only available in Debug builds – markmnl Nov 12 '16 at 04:24
  • Not correct: StackTrace will be avaible when you also deploy .pdb files in release mode. http://stackoverflow.com/questions/2345957/access-the-stacktrace-when-deploying-in-release-mode – T-moty Nov 12 '16 at 09:35
  • I got your point. Is not acceptable that a method works only when PDB files are deployed. I will edit the answer – T-moty Nov 12 '16 at 10:00
0

When your member is static, you will always know what type it is part of at runtime. In this case:

class A
{
  public static int GetInt(){}

}
class B : A {}

You cannot call (edit: apparently, you can, see comment below, but you would still be calling into A):

B.GetInt();

because the member is static, it does not play part in inheritance scenarios. Ergo, you always know that the type is A.

Teun D
  • 5,045
  • 1
  • 34
  • 44
  • 4
    You *can* call B.GetInt() - at least, you could if it weren't private - but the compile will translate it into a call to A.GetInt(). Try it! – Jon Skeet Jan 17 '10 at 17:03
  • Note on Jon's comment: default visibility in C# is private, hence your example doesn't work. – Dan Rosenstark Jan 17 '10 at 17:33
0

For my purposes, I like @T-moty's idea. Even though I have used "self-referencing type" information for years, referencing the base class is harder to do later.

For example (using @Rob Leclerc example from above):

public class ChildA: Parent<ChildA>
{
}

public class ChildB: Parent<ChildB>
{
}

Working with this pattern can be challenging, for example; how do you return the base class from a function call?

public Parent<???> GetParent() {}

Or when type casting?

var c = (Parent<???>) GetSomeParent();

So, I try to avoid it when I can, and use it when I must. If you must, I would suggest that you follow this pattern:

class BaseClass
{
    // All non-derived class methods goes here...

    // For example:
    public int Id { get; private set; }
    public string Name { get; private set; }
    public void Run() {}
}

class BaseClass<TSelfReferenceType> : BaseClass
{
    // All derived class methods goes here...

    // For example:
    public TSelfReferenceType Foo() {}
    public void Bar(TSelfRefenceType obj) {}
}

Now you can (more) easily work with the BaseClass. However, there are times, like my current situation, where exposing the derived class, from within the base class, isn't needed and using @M-moty's suggestion just might be the right approach.

However, using @M-moty's code only works as long as the base class doesn't contain any instance constructors in the call stack. Unfortunately my base classes do use instance constructors.

Therefore, here's my extension method that take into account base class 'instance' constructors:

public static class TypeExtensions
{
    public static Type GetDrivedType(this Type type, int maxSearchDepth = 10)
    {
        if (maxSearchDepth < 0)
            throw new ArgumentOutOfRangeException(nameof(maxSearchDepth), "Must be greater than 0.");

        const int skipFrames = 2;  // Skip the call to self, skip the call to the static Ctor.
        var stack = new StackTrace();
        var maxCount = Math.Min(maxSearchDepth + skipFrames + 1, stack.FrameCount);
        var frame = skipFrames;

        // Skip all the base class 'instance' ctor calls. 
        //
        while (frame < maxCount)
        {
            var method = stack.GetFrame(frame).GetMethod();
            var declaringType = method.DeclaringType;

            if (type.IsAssignableFrom(declaringType))
                return declaringType;

            frame++;
        }

        return null;
    }
}
Kabua
  • 889
  • 8
  • 19