在扩展方法中使用显式强制转换

时间:2013-04-03 21:30:21

标签: c# casting extension-methods

当我尝试通过扩展方法强制转换对象时,我遇到了一个奇怪的问题。我有一个类,我在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

据我所知,在这种特殊情况下,我可以简单地使用getter公开IPAddress,但我们也有更复杂的显式转换,我希望这样做。

修改

感谢Chris Sinclair对使用dynamic的评论,我已将更新扩展方法更新为:

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

使用dynamic会有一些开销,但它足以满足我的需求。它似乎也适用于我尝试的所有基本类型铸件。

1 个答案:

答案 0 :(得分:7)

在第一个示例中,您正在访问用户定义的转换。这仅在演员操作员知道输入类型为PrefixLengthAddress时才可用。在通用代码中,编译器只知道类型objectT。在这种情况下,它无法访问PrefixLengthAddress上定义的转换。

在这种情况下,你正在做的事情更接近于映射与投射,因为它实际上是在创建一个新值。就LINQ而言,您希望使用SelectCast