簡體   English   中英

從base的類靜態方法獲取派生類類型

[英]Get derived class type from a base's class static method

我想從其基類​​的靜態方法獲取派生類的類型。

如何實現這一目標?

謝謝!

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<T>
    where T : BaseClass<T>
{
    static void SomeMethod() {
        var t = typeof(T);  // gets type of derived class
    }
}

class DerivedClass : BaseClass<DerivedClass> {}

調用方法:

DerivedClass.SomeMethod();

此解決方案會增加少量樣板開銷,因為您必須使用派生類對基類進行模板化。

如果您的繼承樹有兩個以上的級別,那么它也是限制性的。 在這種情況下,您必須選擇是否通過模板參數或在其子項上強制使用靜態方法的調用。

當然,通過模板我的意思是泛型。

如果我沒有弄錯的話,為BaseClass.Ping()DerivedClass.Ping()發出的代碼是相同的,所以使方法靜態而不給它任何參數是行不通的。 嘗試將類型作為參數傳遞或通過泛型類型參數(您可以在其上強制執行繼承約束)。

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

你會這樣稱呼它:

BaseClass.Ping<DerivedClass>();

在類型上定義靜態方法。 沒有“這個”。 您需要將此實例方法改為:

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

總之,這是我試圖在這里回答的問題 它使用一個接口來統一所有派生類,並讓它們從基類調用相同的靜態方法而不傳遞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();    
    }
}

我認為以下內容適用於本案例(以及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中只有一個元素,但它取決於應用程序的細節。 將需要一些實驗。

從靜態方法獲取派生類是不可能的。 作為一個例子來說明原因,想象BaseClass有2個子類 - DerivedClass和AnotherDerivedClass - 應該返回哪一個? 與多態非靜態方法不同,在基類上調用靜態方法的派生類沒有可能的關聯 - 編譯時類型和運行時類型與靜態方法調用相同。

您可以使方法非靜態,因此您可以通過多態獲取正確的類型,或者在子類中創建靜態方法“覆蓋”,例如

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

然后,您的客戶端代碼可以調用派生類中的方法,以明確指示它是否需要派生類版本。 如有必要,您還可以將DerivedClass類型作為參數傳遞給基類方法,以提供通過派生類調用該方法的上下文。

只是一個猜測(沒有測試)

Type t = MethodBase.GetCurrentMethod().DeclaringType;

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

如果你有

class BaseClass {}
partial class DerivedClass : BaseClass {}

你可以看看

DerivedClass.GetType().BaseType;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM