Get derived class type from a base's class static method

前端 未结 8 948
走了就别回头了
走了就别回头了 2020-12-01 14:44

i would like to get the type of the derived class from a static method of its base class.

How can this be accomplished?

Thanks!

class BaseCla         


        
相关标签:
8条回答
  • 2020-12-01 14:46

    If I'm not mistaken, the code emitted for BaseClass.Ping() and DerivedClass.Ping() is the same, so making the method static without giving it any arguments won't work. Try passing the type as an argument or through a generic type parameter (on which you can enforce an inheritance constraint).

    class BaseClass {
        static void Ping<T>() where T : BaseClass {
            Type t = typeof(T);
        }
    }
    

    You would call it like this:

    BaseClass.Ping<DerivedClass>();
    
    0 讨论(0)
  • A static method is defined on the type. There is no "this". You'll need to make this an instance method, instead:

    class BaseClass {
        public void Ping() {
            Type t = this.GetType(); // This will work, since "this" has meaning here...
        }
    

    You can then do:

    class DerivedClass : BaseClass {}
    
    DerivedClass instance = new DerivedClass();
    instance.Ping();
    
    0 讨论(0)
  • 2020-12-01 14:49

    Just a guess (not tested)

    Type t = MethodBase.GetCurrentMethod().DeclaringType;
    
    0 讨论(0)
  • 2020-12-01 14:54

    It's not possible to get the derived class from a static method. As an example to illustrate why, imagine BaseClass has 2 subclasses - DerivedClass and AnotherDerivedClass - which one should be returned? Unlike polymorphic non-static methods, there is no possible association with a derived class calling a static method on a base class - the compile time type and runtime type are the same with a static method call.

    You can either make the method non-static, so you then get the correct type via polymorphism, or create static method "overrides" in the subclasses, e.g.

    class DerivedClass : BaseClass
    {
       void Ping() { 
         BaseClass.Ping();
         // or alternatively
         BaseClass.Ping(Type.GetType("DerivedClass"));
       }
    }
    

    Your client code can then call the method in the derived class to explicitly indicate it want's the derived class version. If necessary, you might then also pass the DerivedClass type as a parameter to the base class method, to provide context that the method was called via the derived class.

    0 讨论(0)
  • 2020-12-01 14:58

    I think the following will work for this case (and several similar ones elsewhere on SO). Perf won't be too good, but if this is infrequent, that won't be a problem.

    Create a stacktrace and parse it looking for a derived class. In the general case this wouldn't be too reliable or might not even work, but in specific cases, like that in the OP, I believe this will work fine. In Powershell:

    $strace = (new-object diagnostics.stacktrace).tostring()
    #
    $frames = $strace -split "   at "
    $typesFromFrames = $frames | select -skip 1| # skip blank line at the beginning
       % { ($_ -split "\(",2)[0]} |                 # Get rid of parameters string
       % {$_.substring(0,$_.lastindexof("."))} |    # Get rid of method name
       $ {$_ -as [type]}
    #
    # In powershell a lot of the frames on the stack have private classes
    #  So $typesFromFrames.count is quite a bit smaller than $frames.count
    #  For the OP, I don't think this will be a problem because:
    #   1. PS isn't being used
    #   2. The derived class in the OP isn't private 
    #        (if it is then tweaks will be needed)
    #
    $derivedOnStack = $typesFromFrames | ? { $_.issubclassof( [BaseClass])}
    

    Hopefully there will just be one element in $derivedOnStack, but it will depend on the particulars of the application. Some experimentation will be required.

    0 讨论(0)
  • 2020-12-01 15:02

    This can be accomplished easily using the curiously recurring template pattern

    class BaseClass<T>
        where T : BaseClass<T>
    {
        static void SomeMethod() {
            var t = typeof(T);  // gets type of derived class
        }
    }
    
    class DerivedClass : BaseClass<DerivedClass> {}
    

    call the method:

    DerivedClass.SomeMethod();
    

    This solution adds a small amount of boilerplate overhead because you have to template the base class with the derived class.

    It's also restrictive if your inheritance tree has more than two levels. In this case, you will have to choose whether to pass through the template argument or impose the current type on its children with respect to calls to your static method.

    And by templates I, of course, mean generics.

    0 讨论(0)
提交回复
热议问题