2011-10-06 109 views
6

我正在試驗流利的擴展方法。使用通用約束與值類型

我有以下簡單的擴展方法來執行安全的強制轉換。

 public static T As<T>(this Object source) 
     where T : class 
    { 
     return source as T; 
    } 

這個效果不錯,但是當我試圖使它直觀的使用值類型與過載

 public static T As<T>(this ValueType source) 
     where T : struct 
    { 
     return (T)source; 
    } 

我遇到了問題。方法解析邏輯總是選擇上面的第一個方法,並給出了一個語法錯誤(準確地說)該結構不是一個類。

有沒有辦法處理上述問題,還是應該在去測試和處理同一方法中的所有類型時去除約束的路線?

====編輯:回答問題====

我編寫本針對3.5框架。我並不是真的想要完成任何事情;這只是上述的一個實驗。我的興趣很激烈,我把一些代碼扔在一起。

我不是特別在意它仍然是一個'安全'的角色。這就是它如何開始的,並且可以通過default()保持安全 - 但這並不是問題和代碼確保「安全」只會模糊的焦點。

至於表現力,沒有value.As<int>()沒有比(int)value更有表現力;但爲什麼該方法的用戶只能「知道」它只能用於引用類型呢?我努力工作的內容更多的是關於該方法的預期行爲,而不是表達性寫作。

代碼段value.As<DateTime>()給出了錯誤「類型'System.DateTime'必須是引用類型才能在通用類型或方法中用作參數'T'.... As(object)」 。從錯誤消息我看到它是解決使用上面的方法,因爲它是需要引用類型。

+0

什麼的C#版本使用你正在用嗎?在.NET 4中,選擇了第二個重載。 –

+1

你的意思是像'object o = 42; var i = o.As ();'給出語法錯誤?或者你能顯示給出它的確切代碼嗎? – svick

+0

@ svick的評論讓我想起了你可能試圖用數據庫結果做的事情,比如DataRow。如果是這樣,則已經有一個擴展方法來將行中的對象值轉換爲適當的類型。 [.Field ](http://msdn.microsoft.com/en-us/library/bb360891.aspx) –

回答

3

在.NET 4中,第二個重載是根據您的代碼示例選擇的。 (也只是針對.NET 3.5進行測試,結果相同。)

int myInt = 1; 
long myLong = myInt.As<long>(); // chooses ValueType version 

但是,這隻能讓我們到下一次崩潰的現場。 (T)source;導致無效的轉換異常。您可以得到圍繞通過編寫方法

public static T As<T>(this ValueType source) 
    where T : struct 
{ 
    return (T)Convert.ChangeType(source, typeof(T)); 
} 

不過,我不知道你實際上希望達到的,因爲我沒有看到立竿見影的好處。 (對於這個問題,這是不是安全source as T對象版本。)例如,如何爲

long myLong = myInt.As<long>(); 

任何更具表現力或更容易比

long myLong = (long)myInt; 
+0

由於ValueType是 - 儘管它的名稱 - 實際上是一個類的類型,後一個公式需要裝箱論據。不幸的是,我真的不認爲有什麼辦法可以讓.net允許基於泛型參數的值類型重載。 – supercat