Reputation: 379
So I have this Object, say DoubleContainer.
public struct DoubleContainer
{
private readonly double _value;
private DoubleContainer(double value)
{
_value = value;
}
public static implicit operator double(DoubleContainer doubleContainer)
{
return doubleContainer._value;
}
public static DoubleContainer Create(double value)
{
return new DoubleContainer(value);
}
}
Casting it works as expected in almost all cases, except where it's passed into a function as an Object.
The following code generates an InvalidCastException if I pass in a DoubleContainer:
public double GetDouble(Object input)
{
return (double)input;
}
I can get it to work if I do use dynamic:
public double GetDouble(Object input)
{
return (double)(dynamic)input;
}
My problem with this solution is that Visual Studio grays out the (dynamic), because it should be redundant, so someone may remove it. Also I don't know if there are any other places in the codebase where this same problem may occur.
Is there anything I can do to my implementation of DoubleContainer what will make my first implementation of GetDouble() work? I tried adding another implicit conversion operator from Object to DoubleContainer, but "user-defined conversions to or from a base class are not allowed"....
Upvotes: 3
Views: 115
Reputation: 101443
You cannot make it work, because you can only unbox boxed struct (this is what you are doing with (double) input
) to the exact undelying type, for the reasons best described in this article by Eric Lippert. So whenever you do (double) someObject
- it will only work if object is actually a double
, not int
, not float
, not DoubleContainer
. If you expect other types - you can better use Convert.ToDouble
. For that to work with your type you need it to implement IConvertible
:
public struct DoubleContainer : IConvertible
{
private readonly double _value;
private DoubleContainer(double value)
{
_value = value;
}
public static implicit operator double(DoubleContainer doubleContainer)
{
return doubleContainer._value;
}
public static DoubleContainer Create(double value)
{
return new DoubleContainer(value);
}
public double ToDouble(IFormatProvider provider) {
return _value;
}
public bool ToBoolean(IFormatProvider provider) {
// delegate to your double
return ((IConvertible) _value).ToBoolean(provider);
}
// ... rest is skipped ...
Then it will work with
public double GetDouble(Object input)
{
return Convert.ToDouble(input);
}
Upvotes: 3
Reputation: 4249
When casting an object to double, compiler does not know that it should call your existing operator double
, so it will not insert any call to your user defined operator double.
When you insert dynamic
in the middle, compiler will generate something like "if this reference has an operator double, call it`, so it works.
So, it actually cannot work as long as you cast a System.Object
to a double, while code suggested by @juharr, slightly modified, will work:
public double GetDouble(Object input)
{
if (input is DoubleContainer)
{
var dc = (DoubleContainer)input;
return (double)dc;
}
return (double)input;
}
EDIT: modified code as per @SergiyKlimkov comment
Upvotes: 1