C#通用运算符

Shi*_*rik 21 c# generics operator-overloading

我试图像这样实现一个泛型运算符:

class Foo
{
   public static T operator +<T>(T a, T b) 
   {
       // Do something with a and b that makes sense for operator + here
   }
}
Run Code Online (Sandbox Code Playgroud)

我真正要做的就是优雅地处理继承.使用Foo中的标准运算符+,其中T代替"Foo",如果有人来自Foo(比如Bar继承Foo),那么Bar + Bar操作仍将返回Foo.我希望用泛型运算符+来解决这个问题,但是我只是得到了上面的语法错误(在<)让我相信这样的代码是不合法的.

有没有办法制作通用运营商?

R. *_*des 18

不,你不能在C#中声明泛型运算符.

运算符和继承并不能很好地混合.

如果你想让Foo + Foo返回一个Foo和Bar + Bar来返回一个Bar,你需要在每个类上定义一个运算符.但是,由于运算符是静态的,因此您无法获得多态性的好处,因为要在编译时决定调用哪个运算符:

Foo x = new Bar();
Foo y = new Bar();
var z = x + y; // calls Foo.operator+;
Run Code Online (Sandbox Code Playgroud)

  • 不过,我不确定我是否会购买您的“考虑另一个有问题的方案”。老实说,操作员在任何方面都不是特殊的。它们只是名称不同寻常的方法。同样,您的问题也可以更改为我有3种方法的情况,这些方法采用“ Foo,Foo”,“ Bar,Bar”或“ Qux,Qux”作为参数。需要哪一个?显然是“ Foo,Foo”之一,因为它是唯一满足类型的。但是我不需要理解为什么他们选择进行此限制。我只接受这是一个限制,然后继续前进。 (2认同)

Rak*_*koo 6

http://www.yoda.arachsys.com/csharp/genericoperators.html

static T Add<T>(T a, T b) {
    //TODO: re-use delegate!
    // declare the parameters
    ParameterExpression paramA = Expression.Parameter(typeof(T), "a"),
        paramB = Expression.Parameter(typeof(T), "b");
    // add the parameters together
    BinaryExpression body = Expression.Add(paramA, paramB);
    // compile it
    Func<T, T, T> add = Expression.Lambda<Func<T, T, T>>(body, paramA, paramB).Compile();
    // call it
    return add(a,b);       
}
Run Code Online (Sandbox Code Playgroud)

  • 说说难以理解.如此多的抽象,很少的意图(暴露).可维护性与可重用性一样重要吗? (3认同)

Mar*_*ell 6

现在在 C# 11 中可以通过static abstract接口方法实现这一点;例如:

public interface IMyInterface<T> where T : IMyInterface<T>
{
    static abstract T operator +(T left, T right);
}
Run Code Online (Sandbox Code Playgroud)

然后您可以通过where T : IMyInterface<T>以下方式使用它:

class Bar
{
    static T Add<T>(T x, T y, T z) where T : IMyInterface<T>
    {
        return x + y + z;
    }
}
Run Code Online (Sandbox Code Playgroud)

但问题T您想要的每一个都需要实现IMyInterface<T>,这对于您无法控制的预定义类型(如、等)来说是不可能的。好消息是 .NET 7可以为您做到这一点,适用于您可能想到的所有类型,因此实际上您不需要定义自己的 API;相反,您可以使用系统定义的接口:intfloatINumber<T>

    static T Add<T>(T x, T y, T z) where T : INumber<T>
    {
        return x + y + z;
    }
Run Code Online (Sandbox Code Playgroud)