2013-04-03 69 views
6

當我試圖通過擴展方法強制轉換對象時,出現了一個奇怪的問題。我有一個課程,我圍繞IPAddress包裝了一些功能。在擴展方法中使用顯式強制轉換

// Dumbed down version of class 
public sealed class PrefixLengthIPAddress 
{ 
    public static explicit operator IPAddress(PrefixLengthIPAddress address) 
    { 
     return (address != null) ? address._address : null; 
    } 

    public PrefixLengthIPAddress(IPAddress address) 
    { 
     _address = address; 
     _length = address.GetLength(); 
    } 

    private readonly ushort _length; 
    private readonly IPAddress _address; 
} 

我不喜歡所有的括號的外觀提取IPAddress出來的對象:

var family = ((IPAddress)prefixLengthAddress).AddressFamily; 

我寧願能夠做這樣的事情:

var family = prefixLengthAddress.CastAs<IPAddress>().AddressFamily; 

爲了做到這一點,我寫了以下擴展方法:

public static T CastAs<T>(this object value) where T : class 
{ 
    return (T)value; 
} 
與此

不幸的是我得到了InvalidCastException

var family = ((IPAddress)prefixLengthAddress).AddressFamily;   // Works 
var family = prefixLengthAddress.CastAs<IPAddress>().AddressFamily; // InvalidCastException 

我明白,在這種特殊情況下,我可以簡單地揭露IPAddress吸氣劑,但我們也有更復雜的顯式轉換,我想這樣做。

編輯

由於使用dynamic克里斯·辛克萊的評論我已經更新了擴展方法是這樣的:

public static T CastAs<T>(this object value) 
{ 
    return (T)((dynamic)value); 
} 

有一些開銷使用dynamic,但它比快更足以滿足我的需求。它似乎也適用於我嘗試過的所有基本類型轉換。

+0

那麼'PrefixLengthIPAddress'在類型層次結構中與'IPAddress'沒有關係,這是問題的根本來源。你會使用這種鑄造代碼的其他情況是什麼?試圖任意強制將類型A的實例強制爲類型B的實例將會失敗。此外,通用實際上是無界的;所以'T'可以是一個'string',並且不會發生操作符重載。我懷疑爲'T'綁定'IPAddress'並不會導致你期望的行爲,即使這樣做了,否則你的擴展是無用的。 – Tejs 2013-04-03 21:34:03

+0

我只是喜歡更好的擴展方法的外觀。如果我試圖將我的對象作爲字符串投射,我希望它以任何方式拋出InvalidCastException。 – lumberjack4 2013-04-03 21:48:58

回答

7

在第一個示例中,您正在訪問用戶定義的轉換。這隻有在演員操作員知道輸入的類型是PrefixLengthAddress時纔可用。在通用代碼中,編譯器只知道類型objectT。在這種情況下,無法訪問在PrefixLengthAddress上定義的轉換。

在這種情況下,你正在做的更接近於映射與鑄造,因爲它實際上是在創建一個新值。在LINQ方面,你會想要使用Select而不是Cast

+0

在擴展方法內引發的異常消息是「無法投射'PrefixLengthIPAddress'類型的對象以鍵入'System.Net.IPAddress'」。那麼它在這種情況下怎麼不知道類型? – lumberjack4 2013-04-03 21:38:34

+0

@ lumberjack4用戶定義的轉換僅由語言編譯器(在本例中爲C#)使用。爲了使用,編譯時必須知道類型。你看到的是運行時間,表示兩種類型之間沒有繼承關係。運行時不會考慮用戶定義的轉換 – JaredPar 2013-04-03 21:41:55

+0

Linq'Enumerable如何。CastIterator '然後呢?當我看到這些代碼是看起來幾乎相同,礦山: 私有靜態的IEnumerable CastIterator (IEnumerable的源) { 的foreach(源obj對象) 收益率回報(TResult)目標文件; } – lumberjack4 2013-04-03 21:45:59