[英]C# Generic Operators
我正在尝试像这样实现一个通用运算符:
class Foo
{
public static T operator +<T>(T a, T b)
{
// Do something with a and b that makes sense for operator + here
}
}
我真正想做的是优雅地处理 inheritance。在 Foo 中使用标准运算符 +,其中 T 代替“Foo”,如果任何人都派生自 Foo(比如 Bar 继承 Foo),那么 Bar + Bar 操作仍然会返回一个 Foo。 我希望用通用运算符 + 来解决这个问题,但我只是得到上面的语法错误(在 <)让我相信这样的代码是不合法的。
有没有办法制作通用运算符?
不,您不能在C#中声明泛型运算符。
运算符和继承并不能很好地融合在一起。
如果希望Foo + Foo返回Foo,而Bar + Bar返回Bar,则需要在每个类上定义一个运算符。 但是,由于运算符是静态的,您将无法获得多态的好处,因为要调用的运算符将在编译时确定:
Foo x = new Bar();
Foo y = new Bar();
var z = x + y; // calls Foo.operator+;
https://jonskeet.uk/csharp/miscutil/usage/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);
}
您可以在通用类Foo中定义运算符。
您也可以创建真正的泛型运算符,但C#编译器不会使用它们。
[System.Runtime.CompilerServices.SpecialName]
public static T op_Addition<T>(T a, T b) { ... }
您不能在C#中声明泛型运算符-我不确定推理的原因,但认为这对于实现团队来说是有用与否的事情(我相信Jon Skeet可能会在此处发表文章,或者当他发表时在他的博客中讨论了他想在C#中看到的东西)。
实际上,您甚至不能在C#中将运算符与泛型一起使用 。
这是因为泛型必须适用于可能提供的所有可能的类型。 这就是为什么当要使用==
时,必须将泛型类型的作用域限定为类,如下所示:
void IsEqual<T>(T x, T y) where T : class
{
return x == y;
}
不幸的是,您不能执行以下操作:
void Add<T>(T x, T y) where T : operator +
{
return x + y;
}
您可能也对我遇到的这篇简短的摘要文章感兴趣。
正在寻找相同的东西,谷歌将我带到了这里。...我对接受的答案不太满意,正在寻找解决方法。
我设法使用泛型实现了这一点。 这是Foo and Bar类:
class Foo
{
private int value;
public Foo(int x)
{
value = x;
}
public virtual int getVal()
{
return value;
}
}
class Bar : Foo
{
private int derivedValue;
public Bar(int x):base(x)
{
derivedValue = x;
}
public override int getVal()
{
return derivedValue;
}
}
然后是一个通用类,其中包含运算符,但仅限于Foo的类型并派生自Foo:
class GenericOp<T> where T : Foo
{
private T value;
public GenericOp(T x)
{
value = x;
}
public static Foo operator +(GenericOp<T> a, GenericOp<T> b)
{
return new Foo(a.value.getVal() + b.value.getVal());
}
}
一些用法代码向您显示总是返回Foo并防止您混合类型:
Foo f1 = new Foo(1);
Foo f2 = new Foo(2);
Bar b1 = new Bar(10);
Bar b2 = new Bar(20);
GenericOp<Foo> left = new GenericOp<Foo>(f1);
GenericOp<Foo> right = new GenericOp<Foo>(f2);
Foo res = left + right;
GenericOp<Bar> left1 = new GenericOp<Bar>(b1);
GenericOp<Bar> right1 = new GenericOp<Bar>(b2);
Foo res1 = left1 + right1;
GenericOp<Foo> left2 = new GenericOp<Foo>(f1);
GenericOp<Bar> right2 = new GenericOp<Bar>(b1);
//Foo res2 = left2 + right2; //this fails and rightfully so.
现在可以在 C# 11 通过static abstract
接口方法; 例如:
public interface IMyInterface<T> where T : IMyInterface<T>
{
static abstract T operator +(T left, T right);
}
然后您可以通过where T: IMyInterface<T>
将其用作:
class Bar
{
static T Add<T>(T x, T y, T z) where T : IMyInterface<T>
{
return x + y + z;
}
}
但是,问题是您想要的每个T
都需要实现IMyInterface<T>
,这对于您无法控制的预定义类型(如int
、 float
等)是不可能的。 好消息是 .NET 7会为您完成此操作,适用于您可能想到的所有类型,因此实际上您不需要定义自己的 API; 相反,您可以使用系统定义的接口INumber<T>
:
static T Add<T>(T x, T y, T z) where T : INumber<T>
{
return x + y + z;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.