Writing implicit and explicit type conversion operators is trivial.
I can find lots of documentation about how to write them, but very little about when, or why to write them.
I've done some investigations into existing implementations; for example, BigInteger from .NET's reference source:
public struct BigInteger : IFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>
{
public static implicit operator BigInteger(Byte value)
{
return new BigInteger(value);
}
public static explicit operator Byte(BigInteger value)
{
return checked((byte)((int)value));
}
}
Given the excerpt above, what is the rational for using an implicit operator when converting from Byte to BigInteger, but using an explicit operator when converting from BigInteger to Byte?
As I mentioned in my comment, my assumption was that implicit operators should always be considered safe, whereas explicit operators may be safe but in some cases may need to be handled.
I found the following documentation on pre-defined implicit operators:
The pre-defined implicit conversions always succeed and never cause
exceptions to be thrown.
Note: Properly designed user-defined implicit conversions should
exhibit these characteristics as well. end note
In addition, the documentation for explicit conversions does not give the same guarantees:
The explicit conversions that are not implicit conversions are
conversions that cannot be proven always to succeed, conversions that
are known possibly to lose information, and conversions across domains
of types sufficiently different to merit explicit notation.
This clearly backs up my assumption that implicit operators must ALWAYS be safe and never require exception handling, whereas explicit operators can and do throw exceptions, as in your example of the explicit operator that is checked.
Related
public static explicit operator int(Author a)
{
return a.Publications.Length;
}
public static implicit operator int(Author a)
{
return a.Publications.Length;
}
why can`t I do this? my teacher asked me to override the implicit and explicit cast for operator int for the Author class. + can I get a explanation for the deep copy :D?
why can`t I do this?
You can't do that because the C# specification says that you cannot, in section 10.10.3.
[...] a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types.
Now you might well say:
Answering a "why" question with "because that's what it says in the spec" is deeply unsatisfying.
You asked a vague question. If you want a more specific answer then ask a more specific question. How about:
What factors might the C# design team have considered when creating this rule?
Any implicit conversion is already a legal explicit conversion. That is, if there is an implicit conversion that allows:
Shape s = whatever;
Fruit f = s;
then
Fruit f = (Fruit)s;
is also legal and must mean the same thing. It would be bizarre if those two statements had different semantics, but in a world where you could declare two different versions of the same conversion, one explicit and one implicit, then the compiler would have to detect this situation and ensure that the right conversion is used.
Conversion logic, particularly user-defined conversion logic, is extremely complex in C#. Removing unnecessary, confusing complications is a good idea.
can I get a explanation for the deep copy
Don't ask two questions in one question. Post a second question if you have a second question.
I suspect your seeing compiler error CS0557.
FYI, if you have an implicit operator there is no need for an explicit too. Implicit means there is no need to do a direct cast.
Explicit:
Author a = new Author();
int i = (int)a;
Implicit:
Author a = new Author();
int i = a;
I did an online assessment and I'm trying to understand the results, and here are a few of the questions I did already:
Get enum value from string
Change to method declaration
So the question is this:
I got this one partially right as well, after reading about the subject I would choose just option A and D, can you guys confirm?
Thanks a lot.
Marco
An implicit conversion does not need a cast:
int a = 10;
long b = a;
An explicit conversion does need a cast:
long a = 10;
int b = (int)a;
To define (not invoke) an implicit conversion, the implicit keyword is used:
public static implicit operator MyOther(MyThis obj);
To define an explicit conversion, the explicit keyword is used:
public static explicit operator MyOther(MyThis obj);
Usually, explicit conversions are used when information might be lost through the conversion, or an exception may occur. For example, converting a 64-bit long integer to a 32-bit int integer might lose the 32 most-significant bits of information.
So, I am sure A is true, B, C and E are false. I don't understand the question for D. If they mean invoking the implicit conversion, then it is false. If they mean defining the implicit conversion, then it is true.
I always thought that the nullable types of the .NET framework where nothing but a nice construct that the framework gave us, but wasn't anything new added to the language itself.
That is, until today, for purposes of a demonstration, I tried to create my own Nullable struct.
I get everything I need, except the capability of doing this:
var myInt = new Nullable<int>(1);
myInt = 1;
The problem is the second statement, as I cannot, by any means, overload the assignment operator.
My question is: Is this a special case in the language where the assignment operator has an overload? If not, how would you approach making that previous example work?
Thanks!
The assignment is question is handled using an implicit operator declared as:
public static implicit operator Nullable<T> (T value)
This is handled without any language-specific features.
The main change to the langauge for nullable support is the ability to write this as:
int? myInt = 1;
You could implement this in your type via:
public static implicit operator Nullable<T> (T value)
{
return new Nullable<T>(value);
}
That being sad, there is a lot of features related to Nullable<T> the C# language and CLR does that can't be duplicated in your code.
Ditto on the other answers, but note that Nullable<T> does do some magic as well.
Quoting from that answer by Lippert
C# automatically lifts operators to nullable. There's no way to say
"automatically lift operators to MyNullable". You can get pretty close
by writing your own user-defined operators though.
C# has special rules for null literals -- you can assign them to
nullable variables, and compare them to nullable values, and the
compiler generates special code for them.
The boxing semantics of nullables are deeply weird and baked into the
runtime. There is no way to emulate them.
Nullable semantics for the is, as and coalescing operators are baked
in to the language.
Nullables do not satisfy the struct constraint. There is no way to
emulate that.
And so on.
Not the assignment operator is overloaded, but the class Nullable<T> specifies an implicit conversion operator which is able to convert T into Nullable<T>.
You can easily add this functionality to your class:
class MyInteger {
private int value;
public MyInteger(int value) { this.value = value; }
public static implicit operator MyInteger(int value) {
return new MyInteger(value);
}
}
And then use the operator in the same way:
MyInteger obj = 123;
According to this page Operator overloading
Note that the assignment operator itself (=) cannot be overloaded.
You can define an implicit operator
I'm studying for the 70-536 exam and now I'm checking the lesson about converting between types and I have doubts.
Always implicit conversion it's a widening conversion? and Explicit conversion it's a narrowing conversion?
Also this is consider an Narrowing conversion?
System.Int32 number32 = 25548612
System.Int16 number16 = (System.Int16) number32;
That narrowing conversions should be explicit, and widening conversions may be implicitly is only a design guideline. It is possible to create conversions that violate this guideline with user defined conversions. It's also possible to use an explicit conversion whenever the types implemented the implicit conversion.
A widening conversion is a conversion where every value of the original type can be represented in the result type.
A narrowing conversion is a conversion where some values of the original type cannot be represented in the result type.
Since some values of Int32 cannot be represented as Int16, this is a narrowing conversion. Depending on the compiler options, values outside the range of Int16 either overflow, or throw an exception.
Contrary to what I previously said, this concept also applies to conversions between base- and derived classes.
You need to thing of types as sets of possible values. And not about which members they have.
Every instance of the derived class is always a valid value of a variable of the base class. So casting from the derived class to the base class is widening, and thus implicit.
Some instances of the base class are not valid values of the derived class(For example they derive from a different subtree, or are instances of the base class itself). So casting from the base class to the derived class is narrowing, and thus explicit.
There are some implicit conversions, that are only widening in a loose sense, where the conversion is lossy.
In particular int/Int32 to float/Single and long/Int64 to double/Double. With these conversions some input values can only be represented approximately in the result type.
You need to look at types as a set of allowed values. Then you see that every instance of the derived class, is also an allowed value for the base class. Thus the conversion from derived to base class is widening.
And conversely there are values of the base class, that are not legal values of the derived class.
You can turn it around:
a narrowing conversion will always be explicit
a widening conversion will be implicit.
Assuming a sane implementation of course.
What might help you more: an implicit conversion should always be 'safe' in the sense that it will not throw an exception. An explicit exception might protest.
You can rely on this for the built-in conversions. For custom conversions these are only guidelines, they can be broken.
Always implicit conversion it's widening conversion???
No. Keep in mind that you can define your own implicit conversions. You can make them widening or not, if you want.
Explicit conversion it's a narrowing conversion??
No, same reasoning.
Also this is consider an Narrowing conversion?
Yes. There's clearly a loss of information.
I have converting this method from vb.net to c#:
Public Shared Widening Operator CType(ByVal items As MyOption()) As MyOptionCollection
Return New MyOptionCollection(items)
End Operator
My complaint is that I do not know what this function can complete. I also want to think of how it is working. I find that "Widening Operator" means that when you cast the cast will work but I don't think I have the full meaning.
How can I convert this to c#? Too can you please send me to where I learn what this does ?
This is a conversion operator that takes array of MyOption references and returns an reference to MyOptionCollection object. "Widening" means that using this conversion, you won't lose any data. "Operator" means that it can be called with special syntax.
In C#, Widening can be replaced with implicit (altough I believe it is not exactly the same). So it'll be:
public static implicit operator MyOptionCollection(MyOption[] items)
{
return new MyOptionCollection(items);
}
You can read about conversion operators in C# at MSDN.
More about widening/narrowing:
When the operator is narrowing, it means that you can possibly lose (some of) your data. Good example is casting from Int64 to Int32. If the value is less than maximal for Int32, the cast will succeed and the value will be persisted. But otherwise it will fail.
Contrary, widening operator can't lose any data, i.e. casting from Int32 to Int64 - you can always do it safely.
A Widening operator is one that can perform a conversion without losing precision/information. As such, it is one that would be safe to declare in C# as an implicit operator.
So the equivalent in C# would be something like:
public static implicit operator MyOptionCollection(MyOption[] items)
{
return New MyOptionCollection(items);
}