从base的类静态方法获取派生类类型

时间:2010-06-17 17:55:22

标签: c# generics reflection inheritance

我想从其基类​​的静态方法中获取派生类的类型。

如何实现这一目标?

谢谢!

class BaseClass {
  static void Ping () {
     Type t = this.GetType(); // should be DerivedClass, but it is not possible with a static method
  }
}
class DerivedClass : BaseClass {}

// somewhere in the code
DerivedClass.Ping();

8 个答案:

答案 0 :(得分:35)

使用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> {}

调用方法:

DerivedClass.SomeMethod();

此解决方案会增加少量的样板开销,因为您必须使用派生类对基类进行模板化。

如果您的继承树有两个以上的级别,那么它也是限制性的。在这种情况下,您必须选择是否通过模板参数或在其子项上强制使用静态方法的调用。

模板我当然是指仿制药。

答案 1 :(得分:14)

如果我没有弄错的话,为BaseClass.Ping()DerivedClass.Ping()发出的代码是相同的,所以使方法静态而不给它任何参数将不起作用。尝试将类型作为参数传递或通过泛型类型参数(您可以在其上强制执行继承约束)。

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

你会这样称呼:

BaseClass.Ping<DerivedClass>();

答案 2 :(得分:4)

在类型上定义静态方法。没有“这个”。您需要将此实例方法改为:

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

然后你可以这样做:

class DerivedClass : BaseClass {}

DerivedClass instance = new DerivedClass();
instance.Ping();

答案 3 :(得分:3)

简而言之,这就是我试图回答的问题here。它使用一个接口来统一所有派生类,并让它们从基类调用相同的静态方法而不传递Type。

public interface IDerived
{
}
public class BaseClass<T> where T : IDerived
{
    public static void Ping()
    {
        //here you have T = the derived type
    }
}
public class DerivedClass : BaseClass<DerivedClass>, IDerived
{
    //with : BaseClass<DerivedClass> we are defining the T above
}
public class ExampleApp
{
    public void Main()
    {
        //here we can call the BaseClass's static method through DerivedClass
        //and it will know what Type calls it
        DerivedClass.Ping();    
    }
}

答案 4 :(得分:0)

无法从静态方法获取派生类。作为一个例子来说明原因,想象BaseClass有2个子类 - DerivedClass和AnotherDerivedClass - 应该返回哪一个?与多态非静态方法不同,在基类上调用静态方法的派生类没有可能的关联 - 编译时类型和运行时类型与静态方法调用相同。

您可以使方法非静态,因此您可以通过多态获取正确的类型,或者在子类中创建静态方法“覆盖”,例如。

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

然后,您的客户端代码可以调用派生类中的方法,以明确指示它是否需要派生类版本。如有必要,您可以将DerivedClass类型作为参数传递给基类方法,以提供通过派生类调用该方法的上下文。

答案 5 :(得分:0)

只是猜测(未经测试)

Type t = MethodBase.GetCurrentMethod().DeclaringType;

答案 6 :(得分:0)

为什么不直接使用已有的方法?

如果你有

class BaseClass {}
partial class DerivedClass : BaseClass {}

你可以看看

DerivedClass.GetType().BaseType;

答案 7 :(得分:0)

我认为以下内容适用于此案例(以及SO上其他几个类似的案例)。 Perf不会太好,但如果这种情况不常见,那就不会有问题了。

创建一个堆栈跟踪并解析它以查找派生类。在一般情况下,这不会太可靠或甚至可能不起作用,但在特定情况下,就像在OP中一样,我相信这样可以正常工作。在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])}

希望$ derivedOnStack中只有一个元素,但它取决于应用程序的细节。将需要一些实验。