how to overload an operator of a generic class wit

2019-09-02 00:35发布

问题:

There have been a lot of similar questions asked but all involve operands of same type or same generic type. This one in particular (How can I use a generic type parameter with an operator overload?) is close to what I am looking for but no answer or work-around.

Is it possible to do something like this for the ‘*’ operator overload:

public class MyNumericClass<T>
{
    public double Value { get; set; }

    //OK but works only for same type operands
    public static double operator *(MyNumericClass<T> left, MyNumericClass<T> right)
    {
        return left.Value * right.Value;
    }

    //****Pseudo Code for different type operands - not OK****
    public static double operator *<TRight>(MyNumericClass<T> left, MyNumericClass<TRight> right)
    {
        return left.Value * right.Value;
    }

    static void Test()
    {
        MyNumericClass<int> i = new MyNumericClass<int>();
        MyNumericClass<int> j = new MyNumericClass<int>();
        MyNumericClass<string> s = new MyNumericClass<string>();
        double r1 = i * j;
        double r2 = i * s; //Operator '*' cannot be applied to operands...
    }
}

I need to have a specific overload for different generic types. A non-generic superclass will not do in this case as I have other overloads of the operator (not shown here) and ambiguous calls will be produced if I use a parameter of superclass type and not the exact generic type.

Is it possible to do this or is there a work-around? Is it possible to use op_Multiply instead? (Tried it but couldn’t make it work).

P.S. I don’t see any reason why something like this should not be possible.

EDIT1 After people's answers and comments I am adding another version of the class with the implicit casts and more overloads to demonstrate the call ambiguity and why the answers provided do not solve my problem. I need to specify the different generic type in my operator overload to resolve this:

public class MyNumericClass<T>
{
    public double Value { get; set; }

    public static implicit operator double(MyNumericClass<T> value)
    {
        return value.Value;
    }

    public static implicit operator MyNumericClass<T>(double value)
    {
        MyNumericClass<T> c = new MyNumericClass<T>();
        c.Value = value;
        return c;
    }

    public static MyNumericClass<T> operator *(double left, MyNumericClass<T> right)
    {
        return left * right.Value;
    }

    public static MyNumericClass<T> operator *(MyNumericClass<T> left, double right)
    {
        return right * left;
    }

    //Does not resolve ambiguity and neither does a base class or interface
    public static double operator *(MyNumericClass<T> left, dynamic right)
    {
        return right * left;
    }

    //OK but work only for same type operands
    public static double operator *(MyNumericClass<T> left, MyNumericClass<T> right)
    {
        return left.Value * right.Value;
    }

    ////****Pseudo Code for different type operands - not OK****
    //public static double operator *<TRight>(MyNumericClass<T> left, MyNumericClass<TRight> right)
    //{
    //    return left.Value * right.Value;
    //}

    static void Test()
    {
        MyNumericClass<int> i = new MyNumericClass<int>();
        MyNumericClass<int> j = new MyNumericClass<int>();
        MyNumericClass<string> s = new MyNumericClass<string>();
        double r1 = i * j;
        double r2 = i * s; //The call is ambiguous...
    }
}

回答1:

It really depends on how you want to use it in the future.
You can either:

Make a non-generic base class which contains Value. The operator then works on the base class.

Implement an interface and use covariance.

Like this:

void Main()
{
    MyNumericClass<int> i = new MyNumericClass<int>();
    MyNumericClass<int> j = new MyNumericClass<int>();
    MyNumericClass<string> s = new MyNumericClass<string>();

    double r1 = i * j;
    double r2 = i * s; 
}

public interface IMyNumericClass<out T> {
    double Value { get; set; }
}

public class MyNumericClass<T> : IMyNumericClass<T>
{
    public double Value { get; set; }

    public static double operator *(MyNumericClass<T> left, MyNumericClass<T> right)
    {
        return left.Value * right.Value;
    }

    public static double operator *(MyNumericClass<T> left, IMyNumericClass<object> right)
    {
        return left.Value * right.Value;
    }
}


回答2:

You might need to do it like this

public class MyNumericClass<T>
{
    public double Value { get; set; }

    //OK but works only for same type operands
    public static double operator *(MyNumericClass<T> left, MyNumericClass<double> right)
    {

        return left.Value * right.Value;
    }
    public static double operator *(MyNumericClass<T> left, MyNumericClass<T> right)
    {

        return left.Value * right.Value;
    }

    static void Test()
    {
        MyNumericClass<int> i = new MyNumericClass<int>();
        MyNumericClass<int> i2 = new MyNumericClass<int>();
        MyNumericClass<double> j = new MyNumericClass<double>();
        double r1 = i * i2;
        double r2 = i * j;
    }
}