Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从基';s类静态方法_C#_Generics_Reflection_Inheritance - Fatal编程技术网

C# 从基';s类静态方法

C# 从基';s类静态方法,c#,generics,reflection,inheritance,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 DerivedCla

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

如何做到这一点

谢谢

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();

在类型上定义了静态方法。没有“这个”。您需要将其作为实例方法,而不是:

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();

从静态方法获取派生类是不可能的。作为说明原因的示例,假设基类有2个子类-DerivedClass和另一个DerivedClass-应该返回哪一个?与多态非静态方法不同,派生类调用基类上的静态方法时,不可能与派生类关联——编译时类型和运行时类型与静态方法调用相同

您可以使方法成为非静态的,这样就可以通过多态性获得正确的类型,或者在子类中创建静态方法“重写”,例如

class DerivedClass : BaseClass
{
   void Ping() { 
     BaseClass.Ping();
     // or alternatively
     BaseClass.Ping(Type.GetType("DerivedClass"));
   }
}
然后,您的客户机代码可以调用派生类中的方法,以显式指示它想要的是派生类版本。如果需要,还可以将DerivedClass类型作为参数传递给基类方法,以提供通过派生类调用该方法的上下文。

只是猜测(未测试)


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

类基类{
静态void Ping(),其中T:BaseClass{
类型t=类型(t);
}
}
你可以这样称呼它:

BaseClass.Ping<DerivedClass>();
BaseClass.Ping();

为什么不使用已有的方法呢

如果你有

class BaseClass {}
partial class DerivedClass : BaseClass {}
你可以看看

DerivedClass.GetType().BaseType;

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

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();    
    }
}
idedrive公共接口
{
}
公共类基类,其中T:iderive
{
公共静态无效Ping()
{
//这里有T=派生类型
}
}
公共类派生类:基类,IDerived
{
//使用:BaseClass,我们定义了上面的T
}
公共类示例应用程序
{
公共图书馆
{
//在这里,我们可以通过DerivedClass调用基类的静态方法
//它会知道什么类型的人叫它
DerivedClass.Ping();
}
}

使用

这个解决方案增加了少量的样板文件开销,因为您必须用派生类模板化基类

如果您的继承树有两个以上的级别,那么它也是有限制的。在这种情况下,您必须选择是传递模板参数,还是将当前类型强加于静态方法调用的子级


当然,我所说的模板指的是泛型。

我认为以下内容适用于这种情况(以及其他类似情况)。性能不会太好,但如果这种情况很少发生,也不会有问题

创建stacktrace并对其进行分析以查找派生类。在一般情况下,这不会太可靠,甚至可能不起作用,但在特定情况下,如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中只有一个元素,但这取决于应用程序的具体情况。需要进行一些实验

如果可能的话,我需要用一个静态方法来完成这个任务。@Marco:那么你需要传入一个实例或一个类型。否则无法获取派生类型。this.GetType()返回基类,而不是DerivedClass。@Luca:this.GetType()将在运行时返回this的类型-如果您实际在派生类中,则该类型将是派生类。刚刚测试过,它返回基类类型。当您定义静态方法时,方法在类型本身(基类)上-没有实例,因此它无法知道它是“派生类”…这是我的实际解决方案,我试图看看是否可以避免派生类中的方法。看看我上面的答案,了解基类的静态方法中派生类的类型伟大的技术!谢谢这个模式帮助我避免了反射为了简单起见,我能够在没有类型约束的情况下让它工作,也就是说,
class BaseClass
@InteXX类型约束不是必需的,但是它是为了防止运行时错误而存在的“防止运行时错误”嗯,很有趣。比如?OP的请求是确定该类的哪个子类型正在调用静态方法。如果让子类将任何类型作为T传递,那么静态方法将获得程序员指定的任何类型,可以是任何类型。静态方法破坏了契约,许多操作可能导致运行时错误,例如强制转换,以及基于类型匹配的任何分支。
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();    
    }
}
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();
$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])}