C# 二元运算符重载中的泛型

Generics in C# binary operator overloading

考虑两个通用的 classes

class Result<T1, T2> {}
class Value<T> {}

是否有某种重载 + 运算符的方法,允许我以在结果中正确捕获类型的方式编写以下内容,即 r 具有类型 Result<int,string>?

Value<int> a;
Value<string> b;
var r = a + b;

我可以这样写:

class Value<T> {
   public static Result<T,T> operator+(Value<T> a, Value<T> b) { ... }
}

哪个适用于任何一对 Value<T>,例如两个 Value<int>,但是当类型不同时呢?

查看之前有关 C# 运算符重载的问题,其中 none 似乎回答了这个特定问题。这一个可能是最接近的:

尝试这样做的动机是,如果 Result<T1, T2> class 有一个将委托作为参数的方法,知道特定类型 T1T2 在编译时可以在调用该方法时从 lambda 表达式中省略类型。

为了在任意两个Value<T>Value<U>上定义运算符+,其中TU是任意类型,运算符需要是通用的。使用一些虚构的语法,它看起来像:

class Value<T> {
    public static Result<T,U> operator+<U>(Value<T> a, Value<U> b) { 
        // create a Result<T, U>
    }
}

但是,自定义操作符的syntax非常严格,完全不像方法声明的那样:

operator_declaration
    : attributes? operator_modifier+ operator_declarator operator_body
    ;
operator_declarator
    : unary_operator_declarator
    | binary_operator_declarator
    | conversion_operator_declarator
    ;
binary_operator_declarator
    : type 'operator' overloadable_binary_operator '(' type identifier ',' type identifier ')'
    ;

overloadable_binary_operator
    : '+'   | '-'   | '*'   | '/'   | '%'   | '&'   | '|'   | '^'   | '<<'
    | right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='
    ;
operator_body
    : block
    | '=>' expression ';'
    | ';'
    ;

虽然它们看起来很像方法声明,但它们的语法以非常不同的方式指定,并且不允许泛型参数。

此外,使用这个假设的泛型运算符需要 type inference, which is applied when invoking a method。这不会在运算符解析期间发生。

作为解决方法,您可以声明一个 Plus 方法:

class Value<T> {
    public Result<T,U> Plus<U>(Value<U> other) { 
        // create a Result<T, U>
    }
}

// You'd be doing a.Plus(b), rather than "a + b"
// You still get the type inference you wanted