2012-09-03 99 views
3

要將值類型轉換爲System.Object - 本身對我來說似乎是「錯誤的」(因爲強制轉換應該將該值轉換爲另一種類型(所以將Int32轉換爲對象應該是一個數據有損的行爲,因爲Object沒有自己的實例狀態)或將接口指針轉換爲父級(這不會影響被指向的對象的狀態,並且是編譯期關注的問題)。在CLR中將值複製到堆並在同一時間丟失接口信息的情況下,當您只想真正執行第一個任務時(將值複製到堆或至少獲取對該堆的引用) ).NET中的強類型裝箱值

Java用強類型Integer和解決了這個問題。爲什麼.NET沒有這個?

我有我自己的實用程序源代碼集合,我喜歡在其他項目中包含它們,並且它們包含自己的強類型盒裝類(如BoxedInt32)的實現,它們覆蓋隱式和顯式轉換運算符,除了不必實際強制轉換爲對象(從而保留類型數據)之外,與向Object轉換的方式相同。所以我可以這樣做:

private BoxedInt32 _reference; 
public Int32 GetValue{ return _reference; } 

那麼爲什麼.NET在四個主要版本之後仍然沒有強類型的盒裝類型呢?

+0

最大的使用案例拳擊是集合和泛型解決了很多這一點。你能否詳細說明爲什麼你需要這些強類型的盒裝類型? – akton

+0

@akton當值被一個程序的多個組件共享但是存在於靜態類的狀態之外時,那麼每個程序組件需要一個對保持對象的引用,當你需要的只是對該值的引用時,它可能會混淆代碼。當所述程序組件不需要將該引用存儲在其自己的狀態中時,'ref'參數只能解決這個問題。 – Dai

+0

你認爲BoxedInt32與只是一個物體會有什麼不同? –

回答

4

沒有意義。您永遠不會直接使用BoxedInt32,因爲如果您事先知道該類型,只會使用int而不是該框。所以唯一有趣的情況是:當我們不知道事先知道該類型時,即處理object時。那麼,價值型拳擊已經完美處理,報告類型爲Int32

Java中存在特定盒裝版本的原因部分是因爲Java泛型通過類型擦除的工作方式非常不同;但是.NET具有真正的泛型,包括值類型,所以這是不必要的。

你可以做你自己的盒子:

public class Box<T> where T : struct { 
    private readonly T value: 
    public Box(T value) { this.value = value; } 
    public T Value { get { return value; } } 
} 

(也許添加更多的功能,比如轉換/平等)。不過 - 再次:沒有任何點。經常內置的拳擊已經處理得更好。

+0

對於實現變異接口的結構類型(例如'List .Enumerator'),轉換爲結構類型與對盒裝結構執行動作之間存在差異。如果結構體可以定義自定義裝箱和取消裝箱方法(前提是裝箱方法的返回類型必須實現結構所做的所有接口,並且必須被接受爲拆箱方法的參數),這些問題可以很好地處理。從CLR的角度來看,這似乎並不困難 - 只要每次看到「盒子」指令時都要檢查JITter ... – supercat

+0

...該類型是否實現了適當的裝箱方法(如果沒有使用默認裝箱),並且當它看到一個「unbox」時檢查是否定義了一個自定義操作符。 – supercat

+0

@supercat但是會解決什麼*問題* –

1

你的問題的根源似乎是一個有關如何鑄造工程,它是什麼誤區:

(因爲鑄造要麼值轉換爲另一種類型...或者一個接口指針轉換爲父親)

當您將一件事情轉換爲另一件事情時發生的所有事情是告訴編譯器「請以稍微不同的方式處理這些隨機數據集合」。這些位根本不應該被轉換或修改。 C#和Java爲了安全而拋出一個類型檢查,但這不是鑄造操作本身的核心。

將代表int32的位集合看作別的東西(例如對象引用)是無意義的,因此Boxing系統會在您背後爲您生成一個包裝。它仍然在流延後的規則 - 編譯器現在可以把這個拳擊包裝作爲對象引用,而原位沒有得到修改

...除了無需實際轉換爲對象(從而保持類型數據)...

同樣,這是基於一個不正確的假設。與上面的解釋一致,由於它不修改值,所以cast會「保留類型數據」,它只是改變了編譯器解釋數據的方式。通過裝箱生成的包裝仍然可以訪問底層數據, - 您可以在裝箱的int上調用.GetType(),它會高興地報告它是一個Int32。 您的BoxedInt32課程只是浪費時間和空間來存儲已有的數據。

**注意:有時在C#中看起來像投射的代碼實際上會通過調用隱式轉換運算符來轉換數據。這不是施法,只是假裝,所以規則不適用。

0

也許會爲這種情況下是有用:

var myDictionary = new Dictionary<int, bool>(); 

// So we could use a BoxedBool here and modify the 
// value set below. 
//var myDictionary = new Dictionary<int, BoxedBool>(); 

myDictionary.Add(1, true); 
myDictionary.Add(2, false); 

foreach (var key in myDictionary.Keys) 
{ 
    myDictionary[key] = false; 
    // Cannot do this as it modified the collection. 
    // If it was a reference type, this would not be a problem? 
}