Johniak
Johniak

Reputation: 991

Get derived type from static method

I want to get derived type from static method.

I want to do something like this

void foo()
{
  this.getType();
}

but in static method

I know that

MethodBase.GetCurrentMethod().DeclaringType

returns base type, but i need derived.

Upvotes: 13

Views: 4494

Answers (4)

Phil
Phil

Reputation: 42991

As you alluded to in a comment, it is possible using generics. Running this - say in LinqPad - will produce 'MyDerivedClass'.

void Main()
{
    MyDerivedClass.DoSomething();
}

abstract class MyBaseClass<T> where T : MyBaseClass<T>
{
    public static void DoSomething()
    {
        Console.WriteLine(typeof(T).Name);
    }
}

class MyDerivedClass : MyBaseClass<MyDerivedClass>
{
}

Upvotes: 0

David
David

Reputation: 4953

7 1/2 years later...

I was wanting to do very much the same thing which is how I found this question. There is a solution that is close to what is being asked for and MAY be useful for others searching this question.

I wanted a static method that would return an instance of the class with all the base settings set for me. The following works:

void Main()
{
    ChildClassA cA = ChildClassA.SetFoo();
}

public abstract class BaseClass
{
    public bool Foo {get; set;}
}

public class ChildClassA : BaseClass
{
    public static ChildClassA SetFoo() => new ChildClassA{Foo = false};
}

public class ChildClassB : BaseClass
{
    public static ChildClassB SetFoo() => new ChildClassB { Foo = false };
}

That's all well and good, but I wanted to put that SetFoo function in the base class so that

  1. I wouldn't have to have so much repetitive code and
  2. To ensure all BaseClass objects have SetFoo.

You cannot do:

    public abstract static BaseClass SetFoo;

because something that is static cannot be abstract. You also cannot do:

    public static BaseClass SetFoo => new BaseClass{ Foo = false };

because you can't new up an abstract class.

What you CAN do, though, is use generics to specify the derived type you want. That would look like this:

void Main()
{
    ChildClassA cA = BaseClass.SetFoo<ChildClassA>();
}

public abstract class BaseClass
{
    public bool Foo {get; set;}
    
    public static T SetFoo<T>() where T:BaseClass, new() => new T{Foo = false };
}

public class ChildClassA : BaseClass
{
    // You can leave this here if you still want to call ChildClassA.SetFoo();
    //public static ChildClassA SetFoo() => new ChildClassA{Foo = false};
}

public class ChildClassB : BaseClass
{
    //Again, you can leave this for ChildClassB.SetFoo()--the compiler won't mind
    //public static ChildClassB SetFoo() => new ChildClassB { Foo = false };
}

This is only a little more clunky than what we really wanted (derived.StaticBase), but it's pretty close.

Upvotes: 2

SWeko
SWeko

Reputation: 30872

I guess you need something like this scenario:

void Main()
{
  Base.StaticMethod(); // should return "Base"
  Derived.StaticMethod();  // should return "Derived"
}


class Base
{
  public static void StaticMethod()
  {
    Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.Name);
  }
}

class Derived: Base 
{
}

This code will, however, return

Base       
Base

This is due to the fact that the static method call is resolved at compile time as a call to the base class, that actually defines it, even if it was called from a derived class. The lines

Base.StaticMethod();
Derived.StaticMethod();

generates the following IL:

IL_0001:  call        Base.StaticMethod
IL_0006:  nop         
IL_0007:  call        Base.StaticMethod

In a word, it cannot be done.

Upvotes: 12

dtb
dtb

Reputation: 217233

Assuming you mean you have something like this

class MyBaseClass
{
    public static void DoSomething()
    {
        Console.WriteLine(/* current class name */);
    }
}

class MyDerivedClass : MyBaseClass
{
}

and want MyDerivedClass.DoSomething(); to print "MyDerivedClass", then the answer is:

There is no solution to your problem. Static methods are not inherited like instance methods. You can refer to DoSomething using MyBaseClass.DoSomething or MyDerivedClass.DoSomething, but both are compiled as calls to MyBaseClass.DoSomething. It is not possible to find out which was used in the source code to make the call.

Upvotes: 16

Related Questions