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使用 getter 来公开 ,但我们也有更复杂的显式转换,我想用它来做这件事。

编辑

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

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

using 有一些开销dynamic,但它的速度足以满足我的需求。它似乎也适用于我尝试过的所有基本类型转换。

4

1 回答 1

7

在第一个示例中,您正在访问用户定义的转换。这仅在强制转换运算符知道输入的类型是 时才可用PrefixLengthAddress。在泛型代码中,编译器只知道类型objectT. 它无法访问PrefixLengthAddress在这种情况下定义的转换。

在这种情况下,您所做的更接近于映射与投射,因为它实际上是在创造一个新的价值。就 LINQ 而言,您可能希望使用Selectvs. Cast.

于 2013-04-03T21:33:52.990 回答