I have a weird problem when I'm trying to cast an object via an extension method. I have a class where I wrap some functionality around an IPAddress
.
// Dumbed down version of classpublic 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;
}
I don't like the look of all the parenthesis to extract the IPAddress
out of the object:
var family = ((IPAddress)prefixLengthAddress).AddressFamily;
I'd rather be able to do something like this:
var family = prefixLengthAddress.CastAs<IPAddress>().AddressFamily;
In order to do this I wrote the following Extension Method:
public static T CastAs<T>(this object value) where T : class{
return (T)value;
}
Unfortunately with this I'm getting an InvalidCastException
:
var family = ((IPAddress)prefixLengthAddress).AddressFamily; // Worksvar family = prefixLengthAddress.CastAs<IPAddress>().AddressFamily; // InvalidCastException
I understand that in this particular case I could simply expose the IPAddress
with a getter, but we also have more complex explicit casts that I would like to do this with.
EDIT
Thanks to Chris Sinclair's comment on using dynamic
I have updated the extension method to look like:
public static T CastAs<T>(this object value){
return (T)((dynamic)value);
}
There is some overhead with using dynamic
, but it is more than fast enough for my needs. It also seems to work with all the basic type casting I've tried.
In the first sample you are accessing the user defined conversion. This is only available when the cast operator knows the type of the input is PrefixLengthAddress
. In the generic code the compiler only knows the type object
and T
. There is no way it can access the conversion defined on PrefixLengthAddress
in this scenario.
In this scenario what you're doing is much closer to mapping vs. casting since it's actually creating a new value. In terms of LINQ you would want to use Select
vs. Cast
.