Overloading Primitive Operator (C#)

2019-07-29 21:48发布

问题:

Is there a way I can overload primitives, for example addition with doubles? I want to automatically round the doubles whenever an operation is performed. My current code is this:

    class Test{
    public static double operator +(double x, double y){
        return Math.Round(x + y)
    }
}

but there's an unfortunate error that says "One of the parameters of a binary operator must be the containing type".

回答1:

You can't overload operators on primitive types. This would cause havoc in your codebase.

What you can do instead, is to create a simple wrapper around the primitive type, let's say RoundedDouble:

public struct RoundedDouble : IEquatable<RoundedDouble>, IComparable<RoundedDouble>
{
    public readonly double Value;

    public RoundedDouble(double value)
    {
        Value = Math.Round(value); // Or anything else
    }

    public static implicit operator RoundedDouble(double value)
    {
        return new RoundedDouble(value);
    }

    public static implicit operator double(RoundedDouble wrapper)
    {
        return wrapper.Value;
    }

    public int GetHashCode()
    {
        return Value.GetHashCode();
    }

    public bool Equals(object other)
    {
        if (other is RoundedDouble)
            return ((RoundedDouble)other).Value == Value;

        return false;
    }

    public string ToString()
    {
        return Value.ToString();
    }

    // Add your operators here, and implement the interfaces
}

This is a structure. It has the same value semantics as a double.

Extend it by adding the operators, and by implementing at least IEquatable<RoundedDouble> and IComparable<RoundedDouble>.



回答2:

No, and this would be horrible. Users using your library would suddenly get different behaviors from their double variables!

You can write and use a wrapper object however:

public struct MyDouble
{
     public double Value {get; set;}

     public MyDouble(double initValue)
     {
         Value = initValue;
     }         

     public static double operator +(MyDouble x, MyDouble y){
        return Math.Round(x.Value + y.Value)
     }
}

You can also make it castable to/from a double, among other options. This way users know they are using your object and won't be surprised when their math operations are rounded.

If you want to assign from a simple double, you would need to define an implicit operator, similar to that of Nullable<T> (source):

 public static implicit operator MyDouble(double value) {
            return new MyDouble(value);
        }