I've borrowed the code below from another question (slightly modified), to use in my code:
internal class PositiveDouble
{
private double _value;
public PositiveDouble(double val)
{
if (val < 0)
throw new ArgumentOutOfRangeException("Value needs to be positive");
_value = val;
}
// This conversion is safe, we can make it implicit
public static implicit operator double(PositiveDouble d)
{
return d._value;
}
// This conversion is not always safe, so we're supposed to make it explicit
public static explicit operator PositiveDouble(double d)
{
return new PositiveDouble(d); // this constructor might throw exception
}
}
The original author of this code correctly adheres to the warnings given in MSDN's implicit & explicit documentation, but here's my question: Is explicit
always necessary in potentially exceptional code?
So, I've got some types in my code (e.g. "Volume") that derive from PositiveDouble and I'd like to be able to set instances conveniently like the first line below:
Volume v = 10; //only allowed by implicit conversion
Volume v = new Volume(10) //required by explicit conversion, but gets messy quick
Being forced to use explicit casts everywhere makes the code much less readable. How does it protects the user? In the semantics of my program, I never expect a Volume to be negative; indeed, if it ever happens I expect an exception to be thrown. So if I use an implicit conversion and it throws, what "unexpected results" might clobber me?
You can use a conversion operator when there is a natural and clear conversion to or from a different type. In general, any unit of measure is a good candidate for this.
The explicit function specifier controls unwanted implicit type conversions. It can only be used in declarations of constructors within a class declaration. For example, except for the default constructor, the constructors in the following class are conversion constructors.
The Implicit Operator According to MSDN, an implicit keyword is used to declare an implicit user-defined type conversion operator. In other words, this gives the power to your C# class, which can accepts any reasonably convertible data type without type casting.
An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.
The C# language specification says under 10.10.3 Conversion operators:
If a user-defined conversion can give rise to exceptions (for example, because the source argument is out of range) or loss of information (such as discarding high-order bits), then that conversion should be defined as an explicit conversion.
Also, from MSDN: implicit (C# Reference):
In general, implicit conversion operators should never throw exceptions and never lose information so that they can be used safely without the programmer's awareness. If a conversion operator cannot meet those criteria, it should be marked explicit.
Considering this, your operator PositiveDouble(double d)
should not be marked implicit
, as Volume v = -1
will throw an exception.
So to answer your question:
Is explicit always necessary in potentially exceptional code?
No, it's not necessary, but it should.
Bordering on opinion-based: if your code is the only code using this conversion, and you find implicit conversion easier to read and/or maintain, feel free to use that.
As for
How does it protect the user?
See MSDN: explicit (C# Reference) mentions:
If a conversion operation can cause exceptions or lose information, you should mark it explicit. This prevents the compiler from silently invoking the conversion operation with possibly unforeseen consequences.
I can't really fathom when this would occur, but again, if you think you never convert from a negative double in your code anywhere, this should not ever throw.
Conversions should be implicit only if they will always succeed. If they can fail or cause loss of information, they should be explicit, because this requires the caller of the conversion operation to intentionally indicate that they want this conversion and therefore are prepared to deal with the outcome, whatever that may be.
We can see this in the framework primitive numeric types; assigning an int
to a long
is an implicit conversion, because it will always succeed with the intended result. Going the other way can cause an OverflowException
in checked context, and can cause truncation (loss of information) in unchecked context, so you are required to indicate that you intended this conversion by explicitly casting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With