2012-03-29 30 views
61

我有以下功能:爲什麼將類型對象的動態轉換爲拋出空引用異常的對象?

public static T TryGetArrayValue<T>(object[] array_, int index_) 
{ 
    ... //some checking goes up here not relevant to question 

    dynamic boxed = array_[index_]; 
    return (T)boxed; 
} 

當我把它以下列方式,

object a = new object(); 
object v = TUtils.TryGetArrayValue<object>(new object[] { a }, 0); 

(T)boxed拋出一個空引用異常。

除了「對象」以外,我放入其他任何類型,它工作得很好。
任何想法這是什麼,以及它爲什麼拋出異常?

編輯: 爲什麼我用動態的原因是轉換類型時,例如爲了避免異常:

double a = 123; 
int v = TUtils.TryGetArrayValue<int>(new object[] { a }, 0); 
+0

檢查鑄造前是否有「boxed」爲空。 – 2012-03-29 18:56:42

+5

這可能是'dynamic'實現的一個錯誤。現在檢查4.5中的這個repros。 – dlev 2012-03-29 19:01:12

+1

Repro - 它的確看起來像一個bug,它是如何處理'dynamic'的 - 這個問題是有效的 – BrokenGlass 2012-03-29 19:02:00

回答

41

我同意與其他應答者誰說,這看起來像一個錯誤。具體來說,它似乎是C#運行時綁定層中的一個錯誤,儘管我沒有徹底調查過它。

我對這個錯誤表示歉意。我將把它報告給C#5測試團隊,我們會看看它是否已經在C#5中報告和修復。(它在最近的beta版本中複製,所以它不太可能已經被報告和修復。 )如果沒有,修復不太可能使其進入最終版本。在這種情況下,我們會考慮可能的服務發佈。

感謝您將此引入我們的注意。如果您覺得entering a Connect issue需要跟蹤它,請隨時這樣做,並請包括指向此StackOverflow問題的鏈接。如果你不這樣做,沒問題;測試團隊會以任何方式瞭解它。

+1

我可以獲得發現錯誤的榮譽提及嗎? :D – bedo 2012-03-29 19:54:44

+28

@bedo:絕對。十點給格蘭芬多! – 2012-03-29 19:55:22

+0

我剛剛標記了另一個問題作爲這個副本。是否向Connect報告了一個錯誤?如果有,可以跟蹤狀態的鏈接? – 2016-05-24 19:04:11

2

它有事情做與動態關鍵字。如果我改變類型爲T盒裝它的作品。

static void Main(string[] args) 
    { 
     object a = new object(); 
     object v = TryGetArrayValue<object>(new object[] { a }, 0); 

     Console.ReadLine(); 
    } 

    public static T TryGetArrayValue<T>(object[] array_, int index_) 
    { 

      T boxed = (T)array_[index_]; 
      return boxed; 

    } 

是否有一個特別的原因,您正在使用動態?在這種情況下,你真的不需要它,因爲你知道什麼類型是提前。如果你看,在你的版本中,盒裝類型不是對象,但它是動態的{object},當試圖轉換爲對象時可能是問題。如果你看看我發佈的這個版本,你會得到一個對象類型並且沒有錯誤。

+0

是的,我有一個使用動態的用例,因爲我想要做這樣的事情: double a = 10923049; int v = TUtils.TryGetArrayValue (new object [] {a},0); 使用動態幫助我執行不同兼容類型的強制轉換。否則它會拋出一個異常。 – bedo 2012-03-29 19:10:15

+0

@bedo與一個名爲TryGetArrayValue的方法,我希望它應該能夠失敗。看到你的意圖只是讓我感到害怕!雖然我是靜態打字和編譯類型檢查的忠實粉絲。 – Jetti 2012-03-29 19:16:57

6

這實在是很奇怪的行爲,在dynamic的執行過程中的確看起來像一個bug。我發現,這個變化不會拋出異常,事實上返回對象:

public static T TryGetArrayValue<T>(object[] array, int index) where T : class 
{ 
    dynamic boxed = array[index]; 
    return boxed as T; 
} 

注意,我必須在方法簽名中添加通用約束,因爲as運營商只能如果T是引用類型。

如果你正在尋找一個解決辦法,你可以使用這個(我知道這是醜陋):

public static T TryGetArrayValue<T>(object[] array, int index) 
{ 
    dynamic boxed = array[index]; 

    if (typeof(T) == typeof(object)) 
     return (T)(boxed as object); 

    return (T)boxed; 
} 
+0

不幸的是我需要它爲原語工作。也許我可以把對象當作特殊情況處理,而不是在我返回時進行投射。 – bedo 2012-03-29 19:18:12

+0

如果您嘗試使用TryGetArrayValue ( – Jetti 2012-03-29 19:18:13

+0

@bedo),這甚至不會編譯 - 我擴展我的答案以顯示如何使用'as'關鍵字解決此問題。 – 2012-03-29 19:28:55

14

這是如何工作的動力問題 - 運行時粘結劑與System.Object轉換的問題,但實際上,這確實不是問題。

我懷疑這是因爲dynamic在運行時本身是總是System.Object。 4.7中的C#語言規範聲明:「動態類型在運行時與對象無法區分。」因此,任何用作動態的對象都只是作爲一個對象存儲。

當您將實際的System.Object實例置於動態時,會在運行時綁定解析中發生導致空引用異常的內容。

然而,任何其他類型這不是System.Object作品 - 甚至參考類型等,沒有缺陷。因此,這應該爲您提供適當的行爲,因爲實際上沒有理由創建一個可以傳遞的System.Object本身的實例 - 您總是需要一些具有其他類型信息的子類。

只要您使用任何「真實」類型,這工作正常。對於〔實施例,下面的作品,即使它傳遞和處理爲Object

public class Program 
{ 
    public static T TryGetArrayValue<T>(object[] array_, int index_) 
    { 

     dynamic boxed = array_[index_]; 
     return (T)boxed; 
    } 

    private static void Main() 
    { 
     int p = 3; 
     object a = p; 
     var objects = new[] { a, 4.5 }; 

     // This works now, since the object is pointing to a class instance 
     object v = TryGetArrayValue<object>(objects, 0); 
     Console.WriteLine(v); 

     // These both also work fine... 
     double d = TryGetArrayValue<double>(objects, 1); 
     Console.WriteLine(d); 
     // Even the "automatic" int conversion works now 
     int i = TryGetArrayValue<int>(objects, 1); 
     Console.WriteLine(i); 
     Console.ReadKey(); 
    } 
} 
+0

太好了,謝謝你的解釋! – bedo 2012-03-29 19:29:14

+0

@bedo我不太明白爲什麼它會以對象失敗,但正如我所說的,在實踐中,至少應該沒有關係;) – 2012-03-29 19:33:52

相關問題