5

I was wondering if it's possible (even via reflection et similia) to get the caller derived-class inside of a called base-class static method.

For example, I've a base-class with a static method defined:

public MyBaseClass {
    public static void MyBaseClassStaticMethod() { /** ... **/ }
}

and a derived-from-it class:

public MyDerivedClass : MyBaseClass { }

then I call:

MyDerivedClass.MyBaseClassStaticMethod()

Is it possibile, inside of method MyBaseClassStaticMethod, to know which is the caller derived type?
(i.e. MyDerivedClass)

I just need a string...

Teejay
  • 7,210
  • 10
  • 45
  • 76
  • This is completely impossible. – SLaks Apr 30 '13 at 14:08
  • @SLaks well, "completely" impossible is not quite true - you could crawl the stack-frames, for example. But there is no *good* approach to it – Marc Gravell Apr 30 '13 at 14:08
  • @MarcGravell: How would that work? The stack trace contains no hint of `MyDerivedClass`. – Daniel Hilgarth Apr 30 '13 at 14:09
  • @MarcGravell: That wouldn't even help, unless you have the full source & Roslyn. – SLaks Apr 30 '13 at 14:11
  • @DanielHilgarth ah, my bad - didn't see that it was static - I was thinking fetch the method-info's declaring type, etc – Marc Gravell Apr 30 '13 at 14:12
  • @MarcGravell: Yeah, `static` is the crucial point here. – Daniel Hilgarth Apr 30 '13 at 14:13
  • Completely impossible is something a bit excessive. Via reflection, you can inspect the full IL of the caller method. Using libraries like http://www.mono-project.com/Cecil you can read every single line of source code and get all the information you need! I was looking for something more accessible. – Teejay Apr 30 '13 at 14:16
  • As shown, it's compiled to `MyBaseClass.MyBaseClassStaticMethod()`. Inspecting the IL will only reveal this. Thus, it is impossible. – Tim S. Apr 30 '13 at 14:18
  • @MarcGravell Also tried crawling of stacktrace but, as Slaks said, it does not contain any reference to `MyDerivedClass`, since the called method is static. – Teejay Apr 30 '13 at 14:19
  • 1
    @Teejay: The compiler replaces `MyDerivedClass` with `MyBaseClass` upon compilation. The information simply *isn't there*. – Daniel Hilgarth Apr 30 '13 at 14:19
  • @TimS. With reflection + Cecil you can also inspect the method containing this line of code: `MyDerivedClass.MyBaseClassStaticMethod()` – Teejay Apr 30 '13 at 14:20
  • 1
    @Teejay: Have you actually tried that? Just open up the assembly in your favorite decompiler - you will see that this information isn't there. – Daniel Hilgarth Apr 30 '13 at 14:22
  • 1
    @DanielHilgarth Oh! Just realized that decompiling with .net Reflector! Please write your comment as an answer, I'll accept it since that's the real point here! – Teejay Apr 30 '13 at 14:25
  • @Teejay: [My answer](http://stackoverflow.com/a/16301970/572644) already contains this information. – Daniel Hilgarth Apr 30 '13 at 14:26
  • @DanielHilgarth Just seen the update! Accepted and up-voted! – Teejay Apr 30 '13 at 14:27
  • @Teejay: Looks like you undid the accept. Is there something new you found out? If so, be sure to post it. – Daniel Hilgarth Apr 30 '13 at 14:32
  • @DanielHilgarth No, it's just my internet connection.... – Teejay Apr 30 '13 at 14:33
  • Never say never. There is a workaround for this, see answer by @Loki. – Steven de Salas Jan 09 '15 at 00:49

4 Answers4

9

Generics in following way can be used to solve your scenario

public class BaseClass<TDerived> where TDerived : BaseClass<TDerived>
{
    public static void LogCallerType()
    {
        Console.WriteLine(typeof(TDerived).Name);
    }
}

public class FooClass : BaseClass<FooClass> { }

public class BooClass : BaseClass<BooClass> { }

class Program
{
    static void Main(string[] args)
    {
        FooClass.LogCallerType();
        BooClass.LogCallerType();
    }
}

This will in turn output the following

1. FooClass
2. BooClass
Steven de Salas
  • 20,944
  • 9
  • 74
  • 82
Loki
  • 286
  • 2
  • 7
6

No, this is not possible - by no means. static methods are not polymorphal and as such this information simply doesn't exist.
Consider redesigning your code.

Update:

Upon compilation, the compiler replaces MyDerivedClass with the class the static method is actually declared on, in your case MyBaseClass.
So even in the IL you don't see MyDerivedClass. The information exists only in your source code. It doesn't exist in your compiled assembly.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Thank you. Actually this is only an attempt to do a runtime-check for programmers' errors, when using this library. I can do without. – Teejay Apr 30 '13 at 14:12
  • This is the correct answer and well explained. The other answers try to work around this limitation by changing the requirements of the OP. – Mladen B. Nov 08 '17 at 11:43
0

A static method is statically bound to a certain class and does not really participate in the inheritance-chain. Thus it does not exist in the derived class. The static method therefor does not know that it was actually used in the derived class.

You can however - through a compiler-trick - access the static member from your derived class. As of this post on MSDN-forum a static member-access from a derived class is translated to a call from the base-class containing the static member. So MyDerivedClass.MyBaseClassStaticMethod is translated to MyBaseClass.MyBaseClassStaticMethod. Thus MethodBase.GetCurrentMethod().DeclaringType will allways return MyBaseClass.

So in short: no, it´s not possible to get the derived type from a static member.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
-1

First of all, the static method will not have access to the instance that is calling it. A static method is different from a normal class method in that it does not have access the 'this' reference to a class instance.

If you passed 'this' as a parameter to the static method, then you can try casting it as follows. Assume you have a number of derived class which you want to test for.

public static void MyBaseClassStaticMethod(MyBaseClass callingInstance)
{
    MyDerivedClass myDerivedClass = callingInstance as MyDerivedClass;
    MyDerivedClass2 myDerivedClass2 = callingInstance as MyDerivedClass2;
    MyDerivedClass3 myDerivedClass3 = callingInstance as MyDefivedClass3;
    ...

    // test for which derived class is calling
    if (myDerivedClass != null)
        ...
    else if (myDerivedClass2 != null)
        ...

    ...
}
Mike
  • 141
  • 3