当我尝试通过扩展方法强制转换对象时,我遇到了一个奇怪的问题。我有一个类,我在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
会有一些开销,但它足以满足我的需求。它似乎也适用于我尝试的所有基本类型铸件。
答案 0 :(得分:7)
在第一个示例中,您正在访问用户定义的转换。这仅在演员操作员知道输入类型为PrefixLengthAddress
时才可用。在通用代码中,编译器只知道类型object
和T
。在这种情况下,它无法访问PrefixLengthAddress
上定义的转换。
在这种情况下,你正在做的事情更接近于映射与投射,因为它实际上是在创建一个新值。就LINQ而言,您希望使用Select
与Cast
。