2016-04-30 159 views
1

好的,這不是一個簡單的問題,代碼將幫助我解釋問題。在自引用中獲得類類型,通用類,靜態構造函數

我需要的是一種方式來獲得在自參考,泛型類的類類型,靜態構造函數

想象一下,你有這樣的代碼:

public class ClassA : BaseClass<ClassA>{ 
} 
public abstract class BaseClass<T> where T : BaseClass<T> { 
    static readonly int _aValue; 
    static BaseClass(){ 
     //here i have code that load _avalue for each kind of T type, based on my own logic 
     _aValue=1; 

     //need to get the real type here 
    } 
    public int GetValue() { 
     return _aValue; 
    } 
} 


ClassA c = new ClassA(); 
Console.WriteLine(c.GetValue()); 

然後當你這樣做

ClassA c = new ClassA(); 
Console.WriteLine(c.GetValue()); 

這裏發生什麼是靜態構造函數被調用,它在我的例子中加載的值爲靜態變量

我需要在靜態構造函數就知道了,如果這就是調用構造函數的類型(泛型類型構造每一個派生類中調用它,所以我想我能做些什麼,我需要)如果T類型實際上是ClassA的

我真正需要的是知道如果我宣佈我的正確的類定義,因爲我還沒有找到一個很好的方法,以確保自參考型的真正的自我引用,因爲在我的測試中,我發現,

ClassX : Message<ClassAAA> 

沒有按當我要強制執行時不會出現錯誤

ClassA : Message<ClassA> 
ClassB : Message<ClassB> 
ClassC : Message<ClassC> 

,而不是

ClassD : Message<DifferentClass> 

任何線索?

我已經使用MethodInfo.GetMethod()。DeclaringType嘗試,但它返回基類

UPDATE OK,讓我試着解釋一點 我的方案,我用這種設計來有定製的消息定義,我在我的客戶端/服務器場景中使用,每個不同的消息派生類必須有一個字節,指定「消息ID」,所以我使用屬性來裝飾我的類,該屬性允許我指定一個枚舉值所以我沒有代碼周圍的幻數)

在我的靜態構造函數消息基類,我使用反射來讀取屬性值並將其存儲到其靜態_aValue成員中,因此每種消息都有其自己的消息ID,並且每次消息類型只加載一次,而不是在實例構造函數期間出於性能原因。 它非常好,我也已經讓說喜歡

[MyAttribute(MyMessages.Ping)] 
public class PingMessage : Message<PingMessage> 

,每當我PingMessage類istantiated,我可以得到它的靜態messageTye價值,我很高興有一個類,問題是,有時發生因爲一個錯誤,我創建像

[MyAttribute(MyMessages.Ping)] 
public class PingMessage : Message<AnotherMessage> 

和通用約束的類不漲編譯時錯誤,因爲AnotherMessage的是,從消息繼承所以它是合法的另一個類,但我想強制執行,如果你從Message繼承,T必須是繼承的類,所以只允許

PingMessage : Message<PingMessage> 

我知道有沒有通用約束允許我這樣做,我當然不能在約束中添加派生類,因爲我不知道我將創建哪些消息(和反正有很多消息它沒有意義),所以我想在消息類型的靜態構造函數中進行類型約束檢查,因爲我已經在那裏做了一些事情,所以在我看來,把它放在我的最佳位置檢查,如果類型沒有錯或類沒有指定屬性,則會出現異常情況

我在技術上可以在我的實例構造函數中做這種檢查,但是性能很重要,所以我不能。

我想讓我的消息實現一個自定義的接口,然後有一個接口的方法來檢查類型,並且只在初始化期間調用它,但是如果可能的話,我正在尋找一個更簡單的方法,但它似乎反射可以這不幫我在這裏

+0

'if(c is ClassA)'? [MSDN](https://msdn.microsoft.com/en-us/library/scekt9xw.aspx) - 該示例似乎與您正在查找的模式相匹配。 –

+0

你不能知道靜態構造函數中的靜態構造函數,因爲它沒有被任何類型「調用」。如果你在實例構造函數中這樣做,並且在類不是自引用時拋出異常? – Evk

+0

你能解釋爲什麼你需要在靜態構造函數中而不是實例構造函數? –

回答

0

我不知道一種方法來防止class X : Message<Y>被宣佈,但你可以限制使用Message子類型只有你想要的。

R Foo<A>(A a) where A : Message<A> 
{ 
    // … 
} 

如果您使用類型反射,它只會在運行時知道您的程序是否有效。旨在尋找可由編譯器檢查的解決方案。

+0

閱讀我的文章中的更新。 我把我的支票放在靜態構造函數中,即使因爲我必須在運行時運行它(如果條件不滿足,它會引發異常),但由於性能原因,我無法在實例構造函數中運行它,問題是該靜態構造函數,afaik,不公開當前類的類型,這就是我正在尋找替代方法 –

+0

@FabioAngela我不明白爲什麼'[MyAttribute(MyMessages.Ping)]'屬性是相關的。我所建議的不需要靜態構造函數或運行時檢查。也許它不適合你的問題,但我現在不確定問題是什麼。 – erisco

0

基類的靜態構造函數在第一次訪問基類時調用。這不需要是派生類實例化,例如當在基類上調用靜態方法時。派生類與基類的靜態構造函數無關。也不可能,因爲多個類可以從相同的通用基類派生。

派生類實例化是基類可以知道你正在處理的派生類的最早時間。您可以在非靜態基類構造函數中測試對象的運行時類型:if (!typeof(T).IsAssignableFrom(this.GetType())) throw new InvalidOperationException();。不利的一面是,它不會在編譯時被捕獲。

+0

閱讀我的文章更新。我不能在一個實例方法中運行它,btw靜態構造函數,在泛型類中,對於每個不同的T被調用一次(並且我在設計中已經利用了這一點) –

+0

基類的靜態構造函數被調用每個「T」但不是每個派生類。即如果多個類從相同的「Base 」派生,則它僅執行一次。基類的靜態構造函數中沒有派生類,儘管您可以使用反射來查找它們。 –

相關問題