Explicit and implicit operator with numeric types and unexpected results

I have never done extensive work with overload operators, especially with implicit and explicit conversions.

However, I have several numerical parameters that are used frequently, so I create the structure as a wrapper around the numerical type in order to type these parameters strongly. Here is an example implementation:

public struct Parameter { private Byte _value; public Byte Value { get { return _value; } } public Parameter(Byte value) { _value = value; } // other methods (GetHashCode, Equals, ToString, etc) public static implicit operator Byte(Parameter value) { return value._value; } public static implicit operator Parameter(Byte value) { return new Parameter(value); } public static explicit operator Int16(Parameter value) { return value._value; } public static explicit operator Parameter(Int16 value) { return new Parameter((Byte)value); } } 

Since I was experimenting with my test implementation to get the hang of explicit and implicit statements, I tried to explicitly use the Int64 type for my Parameter , and to my surprise, he didn't throw an exception and even more surprisingly, he simply truncated the number and moved on. I tried to exclude the user explicit operator, and it still behaved the same way.

 public void TestCast() { try { var i = 12000000146; var p = (Parameter)i; var d = (Double)p; Console.WriteLine(i); //Writes 12000000146 Console.WriteLine(p); //Writes 146 Console.WriteLine(d); //Writes 146 } catch (Exception ex) { Console.WriteLine(ex.Message); //Code not reached } } 

So, I repeated my experiment with a simple Byte instead of my structure and had the exact same behavior, so it is obvious that this is the expected behavior, but I thought that an explicit cast leading to data loss would throw an exception.

+2
explicit c # implicit operator-keyword
source share
2 answers

When the compiler parses an explicit user-defined transform , it is allowed to put the explicit inline transform on "on both sides" (or both) of the transform. So, for example, if you have a custom conversion from int to Fred, and you have:

 int? x = whatever; Fred f = (Fred)x; 

then the compiler explains: "there is an explicit conversion from int to Fred, so I can do an explicit conversion from int? to int, and then convert int to Fred.

In your example, there is a built-in explicit conversion from long to short, and there is an explicit user-defined conversion with a short parameter value, so converting long to parameter is legal.

The same applies to implicit conversions; the compiler can insert inline implicit conversions on each side of the custom implicit transform.

The compiler never binds two user conversions.

Building your own explicit conversions properly is a difficult task in C #, and I urge you to stop trying to do this until you have a complete and thorough understanding of the entire chapter of the specification that covers conversions.

For some interesting aspects of chained conversions, see my related articles:

http://blogs.msdn.com/b/ericlippert/archive/2007/04/16/chained-user-defined-explicit-conversions-in-c.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/04/18/chained-user-defined-explicit-conversions-in-c-part-two.aspx

+7
source share

This goal:

so I create a structure like a wrapper around a numeric type to force input these parameters

And this code:

 public static implicit operator Byte(Parameter value) { return value._value; } public static implicit operator Parameter(Byte value) { return new Parameter(value); } 

The complete contradiction. By adding two-way implicit statements, you invalidate any type of security that the shell can bring.

So leave the implicit conversions. You can change them to explicit.

+3
source share

All Articles