[英]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.