How do implicit conversions work with operator overloading? - c#

If I were to, say, create a thin wrapper around the float type for whatever reason, like so:
public class WrappedFloat
{
private float value;
public WrappedFloat(float value)
{
this.value = value;
}
public static implicit operator float(WrappedFloat wrapped)
{
return wrapped.value;
}
public static implicit operator WrappedFloat(float value)
{
return new WrappedFloat(value);
}
}
This code is apparently perfectly valid:
new WrappedFloat(4.0F) + new WrappedFloat(3.0F)
Since WrappedFloat doesn't define any arithmetic operators, there must be something about it's implicit conversion to float allowing this. But operator overloading is just syntactic sugar for methods, right? It's not like I can call methods (i.e. CompareTo) on WrappedFloat just because float has them. So what's so special about operators here? What are the rules for allowing this?

Operators are, for the purposes of this discussion, just like static methods. Imagine you had an actual static method for each operator overload:
public static int Plus(int a, int b) { return a + b; }
public static float Plus(float a, float b) { return a + b; }
public static long Plus(long a, long b) { return a + b; }
public static string Plus(string a, string b) { return a + b; }
public static double Plus(double a, double b) { return a + b; }
//...
Now imagine you have:
Plus(new WrappedFloat(4.0F), new WrappedFloat(3.0F));
What would you expect to happen here? Overload resolution would run, it would see that there is an overload for which both of the parameters have an implicit conversion to, and that overload (accepting float values) becomes the unique best match.
The exact same thing happens with operators. It pulls together all of the overloads, sees which ones have argument lists for which the provided arguments can be implicitly converted to, and then chooses the best match among them if there are multiple.

But operator overloading is just syntactic sugar for methods, right?
It is not syntactic sugar for "methods", it is syntactic sugar for one kind of method implemented in a specific way. The typical method call on an object with . syntax is not applicable here. MS chose a design for programmer convenience. When I call
wrappedFloat.Method()
I dont expect it to look for every possibility on wrappedFloat, but when I do
wrappedFloat1 + wrappedFloat2
I expect it to. I agree with MS here. One difference here, is that in first case it is a call on the instance, the second one is a static method call where the formal parameter is passed as an argument.

Related

Defining operators for specific instances of a generic

I am attempting to implement the generic Vector3 struct, and havethe operators for my struct that allows basic math when the type T is a numeric (int, float, double, long, short)
I had thought the way to do this was to just define the 4 basic operators for all each something like
public static Vector3<int> operator +(Vector3<int> left, Vector3<int> right)
but that gives me the error that at least one of the parameters must be of the containing type (which is Vector3 in this case)
I feel reasonably confident there is a way for me to define a Vector3 generic, and still have the convenience of the standard operators, but I can not seem to figure out what I need to write syntactically.
I believe you are trying to do something like this:
public class Vector3<T>
{
T x; T y; T z;
public static Vector3<int> operator + (Vector3<int> lhs, Vector3<int> rhs)
{
//Stuff
}
}
This is not allowed. Why not? Well imagine you wrote a method like this:
public static void Foo<T>()
{
var lhs = new Vector3<T>();
var rhs = new Vector3<T>();
var result = lhs + rhs;
}
Should the compiler allow this to compile or not? Because this would work:
Foo<int>();
But this would fail:
Foo<string>();
Because the compiler can't guarantee it'll work, it's not allowed.
If you have a burning desire to implement operator overloading for certain types of Vector3, you have to subclass it:
public class Vector3Int : Vector3<int>
{
public static Vector3Int operator + (Vector3Int lhs, Vector3Int rhs)
{
//Stuff
}
}
That would work. Note that I had to change struct to class as you can't inherit a struct.

Can I overload a "cast from null" operator in C#?

I have a struct type in C#. I want to be able to convert null implicitly to this type. For instance, null could be represented by a special value of the struct type and the cast operator should return a struct with this value.
In C++, I could use an implicit cast operator overload of type std::nullptr_t. Is there a comparable type in C#?
I have had the idea to use a special NullType class which has no instances. This works but looks somehow ugly. Is there a better way?
Example:
class NullType
{
private NullType(){} // ensures that no instance will ever be created
}
struct X
{
private static readonly int nullValue = -1;
private int val;
public X(int val){ this.val= val; }
public static implicit operator X(NullType t)
{
return new X(nullValue);
}
}
class MainClass
{
public static void Main(string[] args)
{
X x = null; // Works now!
}
}
No, conversion operators only allow conversion from types, not from a specific value of a type, aka null, so there is no null conversion operator.
The best fitting operator without introducing own types would be this:
public static implicit operator X(object t)
But obviously you don't want to use this. It isn't very safe to use (t can be any value, and the only way to handle non-null cases in an exception).
That said, I think the way you've created it now, using a class that can't be initialized is the best way to do this. In fact the only question is: why do you want to use null, instead of 'just' an default value instance on your struct (X.Null).

How can I convert a string to a custom type so a DataGridView can write to an object of that type?

A colleague developed a set of classes to manage various types of measurements so that the unit of measurement (deg F, deg C, or whatever) can be specified at run time. The classes have a ToString() method that returns a string containing the value and the unit, such as "100 C".
There is a class that has several members of these types. For the purpose of this question, let's work with CSimUnitTemperature. The class has implicit conversion operators for doubles:
// Type Casting
public static implicit operator double(SimUnitTemperature T) { return T.Temperature; }
public static implicit operator SimUnitTemperature(double temp)
{
SimUnitTemperature T = new SimUnitTemperature();
T.Temperature = temp;
return T;
}
The CSimRecipeSegment class has several members of type SimUnitTemperature. I can create a List object and use it as a data source for a DataGridView. But when I try to change a value shown as "100 C" to "110 C", I get a long exception message beginning with "Invalid cast from 'System.String' to 'SimShopMeasures.SimUnitTemperature'.
So, I tried to provide an implicit conversion from a string to a SimUnitTmeperature object, using a little string extension method I wrote that converts the first piece of a string into a double:
public static implicit operator string(SimUnitTemperature T)
{
return T.ToString();
}
public static implicit operator SimUnitTemperature(string tempString)
{
SimUnitTemperature T = new SimUnitTemperature();
T.Temperature = tempString.FirstValue();
return T;
}
But when I tried to use this, I got the same exception. Breakpoints on both of these methods were not hit when I tried to change a value in the DataGridView.
I know I can add public properties of type double to the class that is using all these temperatures, and that's probably what I'll do, but I think it would be cleaner to change the SimUnitTemperature class to let me do this.
Thank you very much.

Casting Between Data Types in C#

I have (for example) an object of type A that I want to be able to cast to type B (similar to how you can cast an int to a float)
Data types A and B are my own.
Is it possible to define the rules by which this casting occurs?
Example
int a = 1;
float b = (float)a;
int c = (int)b;
Yes, this is possible using C# operator overloading. There are two versions explicit and implicit.
Here is a full example:
class Program
{
static void Main(string[] args)
{
A a1 = new A(1);
B b1 = a1;
B b2 = new B(1.1);
A a2 = (A)b2;
}
}
class A
{
public int Foo;
public A(int foo)
{
this.Foo = foo;
}
public static implicit operator B(A a)
{
return new B(a.Foo);
}
}
class B
{
public double Bar;
public B(double bar)
{
this.Bar = bar;
}
public static explicit operator A(B b)
{
return new A((int)b.Bar);
}
}
Type A can be cast implicitly to type B but type B must be cast explicitly to type A.
Assuming you want that to be an explcit operation you'll need to write an explicit cast operator like so:
public static explicit operator MyTypeOne(MyTypeTwo i)
{
// code to convert from MyTypeTwo to MyTypeOne
}
You can then use it like so:
MyTypeOne a = new MyTypeOne();
MyTypeTwo b = (MyTypeTwo)a;
I'd question whether you want to actually cast one type to another, or whether you actually want to convert instead. I'd say you should avoid writing cast operators for conversions, if you are just aiming to take advantage of a nice syntax :)
Also, in general it is advised not to use implicit casts, as they allow for unintended type converstions. From MSDN documentation on implicit:
However, because implicit conversions
can occur without the programmer's
specifying them, care must be taken to
prevent unpleasant surprises. 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.
You cant overload the cast operator in c# but you can use explicit and implicit conversion operators instead:
"Using Conversion Operators (C# Programming Guide)"

Will the c# compiler perform multiple implicit conversions to get from one type to another?

Let's say you have yourself a class like the following:
public sealed class StringToInt {
private string _myString;
private StringToInt(string value)
{
_myString = value;
} public static implicit operator int(StringToInt obj)
{
return Convert.ToInt32(obj._myString);
}
public static implicit operator string(StringToInt obj)
{
return obj._myString;
}
public static implicit operator StringToInt(string obj)
{
return new StringToInt(obj);
}
public static implicit operator StringToInt(int obj)
{
return new StringToInt(obj.ToString());
}
}
Will you then be able to write code like the following:
MyClass.SomeMethodThatOnlyTakesAnInt(aString);
without it stating that there is no implicit cast from string to int?
[Yes, i could test it myself but i thought i would put it out there and see what all of the gurus have to say]
No C# won't call more than one user defined implicit conversion. From the C# spec section 6.4.3:
Evaluation of a user-defined conversion never involves more than one user-defined or lifted conversion operator. In other words, a conversion from type S to type T will never first execute a user-defined conversion from S to X and then execute a user-defined conversion from X to T.
I am fairly certain this is not possible under C# 3.0. The sections in the reference that covers conversions is 6.4. Namely, 6.4.4 "User-defined implicit conversions".
It only talks about conversions from S->T (and not S->T->U) which covers the cases such as:
StringToInt _t = "foo";
int t = _t;
and
int t = (StringToInt)"foo";
Where both of these cases only involve S->T (twice).
I am pretty sure this is not possible in C# 3.0.
Allowing S->T->U would require much more work to be performed by the type matcher, at least following the algorithm specified.
It does not appear to work. It requires at least one explicit cast. Oh well...
Typos in your snippet:
public StringToInt(string value)
{
_myString = value;
}
public static implicit operator int(StringToInt obj)
{
return Convert.ToInt32(obj._myString);
}
public static implicit operator string(StringToInt obj)
{
return obj._myString;
}
If aString is of type StringToInt, your usage should work.

Categories

Resources