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

lum*_*ck4 6 c# extension-methods casting

当我试图通过扩展方法强制转换对象时,我遇到了一个奇怪的问题.我有一个类,我在其中包含一些功能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;
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢所有括号的外观来提取IPAddress出对象:

var family = ((IPAddress)prefixLengthAddress).AddressFamily;
Run Code Online (Sandbox Code Playgroud)

我宁愿做这样的事情:

var family = prefixLengthAddress.CastAs<IPAddress>().AddressFamily;
Run Code Online (Sandbox Code Playgroud)

为了做到这一点,我写了以下扩展方法:

public static T CastAs<T>(this object value) where T : class
{
    return (T)value;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我得到了一个InvalidCastException:

var family = ((IPAddress)prefixLengthAddress).AddressFamily;         // Works
var family = prefixLengthAddress.CastAs<IPAddress>().AddressFamily;  // InvalidCastException
Run Code Online (Sandbox Code Playgroud)

我理解在这种特殊情况下我可以简单地IPAddress用getter 公开它,但我们也有更复杂的显式转换,我想这样做.

编辑

感谢Chris Sinclair对使用的评论dynamic我更新了扩展方法,如下所示:

public static T CastAs<T>(this object value)
{
    return (T)((dynamic)value);
}
Run Code Online (Sandbox Code Playgroud)

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

Jar*_*Par 7

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

在这种情况下,您正在做的事情更接近于映射与投射,因为它实际上创建了一个新值.就LINQ而言,你会想要使用Selectvs Cast..

  • @ lumberjack4有用吗?如果`source`具有不是_castable_的对象,那么它应该抛出异常."显式运算符"(大多数)只是语法糖.它们不能从类型`object`应用到类型`T`._might_可能是首先强制转换为`dynamic`:`return(T)(dynamic)value;`但是这会在运行时解析显式转换时产生运行时成本.我之前看到它使用了这样的东西(但是我的头顶,我不是_positive_这是_exact_场景) (2认同)