2011-09-29 106 views
10

Nullable<T>的定義是:爲什麼我不能寫Nullable <Nullable <int>>?

[SerializableAttribute] 
public struct Nullable<T> where T : struct, new() 

約束where T : struct意味着T只能是值類型。所以我非常好理解,我不能寫:

Nullable<string> a; //error. makes sense to me 

因爲string是引用類型,不是值類型。但我不明白爲什麼我不能寫

Nullable<Nullable<int>> b; //error. but why? 

爲什麼不允許?畢竟,Nullable<int>是一個值類型,因此它可以是Nullablle<T>的類型參數。

當我編譯它ideone,它給這個錯誤(ideone):

錯誤CS0453: '詮釋' 的類型必須是一個非空值類型,以便在通用類型或方法使用它作爲類型參數「T」「System.Nullable」 編譯失敗:1個誤差(S),0警告

+0

錯誤是什麼? – asawyer

+2

對不起,我的回答是錯誤的。 'new Nullable ();'編譯(產生一個值爲null的int?'),儘管默認構造函數沒有記錄。 – BoltClock

+0

是的,答案出現在您嘗試編譯代碼時應該得到的錯誤中。 – BoltClock

回答

5

從C#語言規範的4.1.10節:

非空值類型相反地比System.Nullable<T>其他任何類型的值和其簡寫T?(對於任何T),以及任何被約束爲非空值類型的類型參數(即任何帶有約束條件的類型參數)。 System.Nullable<T>類型指定T(第10.1.5節)的值類型約束,這意味着可爲空類型的基礎類型可以是任何不可爲空值的類型。可爲空的類型的基礎類型不能是可爲空的類型或引用類型。例如,int??string?是無效的類型。

9

因爲它是在C#規範(第4.4.4節):

如果約束爲值類型約束(結構),該類型A必須滿足下列之一:

  • A是結構類型或枚舉類型,但不是可空類型。請注意,System.ValueType和System.Enum是不符合此約束條件的引用類型。
  • A是一個具有值類型約束的類型參數(第10.1.5節)。
+0

請擴大規格報價。我並不完全明白這一點。我是C#的新手。 – Nawaz

+0

您應用於類的'struct'泛型類型約束是_specified_,意思是'除'Nullable '之外的所有值和枚舉類型',特別是用於停止這種循環。 – thecoop

+0

@thecoop:這不是一個奇點。如果不是'Nullable'的類型參數的'struct'約束,可以有用''包含一個方法'Nullable 'TryGetValue(TKey)',而不必使用'out'參數。鑑於'Dictionary > myDict',在'var it = myDict.TryGetValue(「Fred」)後面;'如果'.HasValue'爲false,那就意味着找不到鍵;如果'it.HasValue'爲true,但是'it.Value.HasValue'爲false,那麼這意味着爲關鍵字「Fred」存儲了一個空值。真正的困難源於MS決定擁有...... – supercat

3

從C#4規範的§10.1.5:

值類型約束指定用於類型參數類型參數必須是一個非空值類型。所有不可爲空的結構類型,枚舉類型和具有值類型約束的類型參數均滿足此約束條件。請注意,雖然分類爲值類型,但是可以爲空類型(§4.1。10)不滿足值類型約束。具有值類型約束的類型參數不能具有構造函數約束。

1

正如其他人所說,規範禁止這一點。

挖越深,這是值得意識到你可以使自己的結構,使這種模式:

struct Nestable<T> where T : struct { /* ... */ } 

new Nestable<Nestable<int>>(); // This works just fine 

嵌套nullables的禁令不能使用提供給您和我的類型系統來表達。它僅在編譯器(CS0453)中由特殊情況強制執行。


旁白:中的問題顯示的new()約束實際上並不在System.Nullable<T>存在。 new()約束在使用struct約束時被禁止。

CS0451:「新()」約束不能用「結構」約束

所有的結構支持默認初始化反正使用。

+0

根據文檔,不再有'new()'約束:https://referencesource.microsoft.com/#mscorlib/system/nullable.cs – series0ne

1

這不完全是一個答案,但只是思考的食物。

回合1

Nullable<Nullable<int>> a;

錯誤CS0453:類型'詮釋?必須是一個非空值類型,以便在通用類型或方法「可爲空」

智能感知提示來使用它作爲參數「T」 ... 該名稱可以被簡化


回合2

Nullable<int?>一個;

錯誤CS0453:類型'int?'必須是一個非空值類型,以便在通用類型或方法「可爲空」

智能感知提示來使用它作爲參數「T」 ... 該名稱可以被簡化


回合3

int?? a;

錯誤CS1519:無效標記'?'在類,結構或接口成員聲明中

錯誤CS1525:無效的表達式'??'


結論

int?基本上只是一個Nullable<int>速記評價,但有作爲int??沒有這樣的事情是我可以看到速記代表Nullable<Nullable<int>>的唯一途徑。加int??借用空合併運算符,所以我很高興這是不可能的,因爲它看起來很可怕。 想象一下int????????????? a;毫無意義。

最後,由於Nullable的參考源沒有產生任何強制執行的約束,我的猜測是這個約束被烘焙到CLR中,作爲一種特殊情況,當可空值類型被引入到C#中時。

相關問題