英文:
How to implement a generic interface with defined return types
问题
I have an interface for my geometric shapes that looks like this:
public interface IGeometry
{
T Translate<T>(in v2 vector) where T : IGeometry;
T MoveTo<T>(in v2 vector) where T : IGeometry;
}
I am confused how I define this in my structs where I specifically return the struct type that implements the interface. I have this in my Circle : IGeometry
struct:
public readonly struct Circle : IGeometry
{
public readonly v2 _o;
public readonly double _r, _area, _circum;
public v2 Origin => _o;
public double Radius => _r;
public double Circumference => _circum;
public Circle(in v2 origin, in double radius)
{
_o = origin;
_r = radius;
_area = _r * _r * Math.PI;
_circum = _r * 2 * Math.PI;
}
public T Translate<T>(in v2 translation) => new Circle(_o + translation, _r);
public T MoveTo<T>(in v2 position) => new Circle(position, _r);
}
The error I get, however, is:
Error CS0425: The constraints for type parameter 'T' of method 'Circle.Translate<T>(in v2)'
must match the constraints for type parameter 'T' of interface method
'IGeometry.Translate<T>(in v2)'. Consider using an explicit interface implementation instead.
Not quite sure I understand how to fix this.
英文:
I have an interface for my geometric shapes that looks like this:
public interface IGeometry
{
T Translate<T>(in v2 vector) where T : IGeometry;
T MoveTo<T>(in v2 vector) where T : IGeometry;
}
I am confused how i define this in my structs where i specifically return the struct type that implements the interface. I have this in my Circle : IGeometry
struct:
public readonly struct Circle : IGeometry
{
public readonly v2 _o;
public readonly double _r, _area, _circum;
public v2 Origin => _o;
public double Radius => _r;
public double Circumference => _circum;
public Circle(in v2 origin, in double radius)
{
_o = origin;
_r = radius;
_area = _r * _r * Math.PI;
_circum = _r * 2 * Math.PI;
}
public T Translate<T>(in v2 translation) => new(_o + translation, _r);
public T MoveTo<T>(in v2 position) => new(position, _r);
}
The error i get however is:
Error CS0425: The constraints for type parameter 'T' of method 'Circle.Translate<T>(in v2)'
must match the constraints for type parameter 'T' of interface method
'IGeometry.Translate<T>(in v2)'. Consider using an explicit interface implementation instead.
Not quite sure I understand how to fix this.
答案1
得分: 3
如果您需要一个具有成员的非泛型版本和泛型版本的接口,那么您确实需要两个接口。这是需要使用方法重写的情况之一。
尝试这些:
public interface IGeometry
{
IGeometry Translate(in v2 vector);
IGeometry MoveTo(in v2 vector);
}
public interface IGeometry<T> : IGeometry where T : IGeometry<T>
{
new T Translate(in v2 vector);
new T MoveTo(in v2 vector);
}
现在,您可以隐式实现泛型接口,以及显式实现非泛型接口。
public readonly struct Circle : IGeometry<Circle>
{
private readonly v2 _o;
private readonly double _r, _area, _circum;
public v2 Origin => _o;
public double Radius => _r;
public double Circumference => _circum;
public Circle(in v2 origin, in double radius)
{
_o = origin;
_r = radius;
_area = _r * _r * Math.PI;
_circum = _r * 2 * Math.PI;
}
public Circle Translate(in v2 translation) => new(_o + translation, _r);
public Circle MoveTo(in v2 position) => new(position, _r);
IGeometry IGeometry.Translate(in v2 vector) => this.Translate(vector);
IGeometry IGeometry.MoveTo(in v2 vector) => this.MoveTo(vector);
}
现在,通过这些您可以这样做:
Circle circle1 = new Circle();
Circle circle2 = circle1.Translate(new v2());
IGeometry geometry1 = circle1;
IGeometry geometry2 = geometry1.Translate(new v2());
Circle circle2a = (Circle)geometry2;
对非泛型接口方法的调用会调用泛型版本以保持类型安全。
但是,请谨记,您可以合法地实现这样的代码:
public readonly struct Square : IGeometry<Circle>
您需要小心不要这样做。
英文:
If you require a non-generic with generic versions of the members then you really need two interfaces. This is one of the circumstances where shadowing methods is necessary.
Try these:
public interface IGeometry
{
IGeometry Translate(in v2 vector);
IGeometry MoveTo(in v2 vector);
}
public interface IGeometry<T> : IGeometry where T : IGeometry<T>
{
new T Translate(in v2 vector);
new T MoveTo(in v2 vector);
}
Now you can implement the generic interface implicitly and the non-generic interface explicitly.
public readonly struct Circle : IGeometry<Circle>
{
private readonly v2 _o;
private readonly double _r, _area, _circum;
public v2 Origin => _o;
public double Radius => _r;
public double Circumference => _circum;
public Circle(in v2 origin, in double radius)
{
_o = origin;
_r = radius;
_area = _r * _r * Math.PI;
_circum = _r * 2 * Math.PI;
}
public Circle Translate(in v2 translation) => new(_o + translation, _r);
public Circle MoveTo(in v2 position) => new(position, _r);
IGeometry IGeometry.Translate(in v2 vector) => this.Translate(vector);
IGeometry IGeometry.MoveTo(in v2 vector) => this.MoveTo(vector);
}
Now with all of that you can do this:
Circle circle1 = new Circle();
Circle circle2 = circle1.Translate(new v2());
IGeometry geometry1 = circle1;
IGeometry geometry2 = geometry1.Translate(new v2());
Circle circle2a = (Circle)geometry2;
Calls to the non-generic interface methods call the generic versions to keep type safety.
However, keep in mind that you could implement this legally:
public readonly struct Square : IGeometry<Circle>
You need to be careful not to.
答案2
得分: 0
接口本身应该是通用的,而不是方法本身,如下所示:
```cs
public interface IGeometry<T> where T : IGeometry<T>
{
T Translate(in v2 vector);
T MoveTo(in v2 vector);
}
然后,您的类型将使用指定的通用类型实现接口:
public readonly struct Circle : IGeometry<Circle>
您可以在BCL的INumber<T>
接口中看到这一点,该接口在所有数字上都实现了:https://learn.microsoft.com/en-us/dotnet/api/system.numerics.inumber-1?view=net-7.0
<details>
<summary>英文:</summary>
The interface itself should be generic, not the methods themselves, like so:
```cs
public interface IGeometry<T> where T : IGeometry<T>
{
T Translate(in v2 vector);
T MoveTo(in v2 vector);
}
Then your typed will implement the interface with that generic specified:
public readonly struct Circle : IGeometry<Circle>
You can see this in the BCL's INumber<T>
interface, which is implemented on all numbers: https://learn.microsoft.com/en-us/dotnet/api/system.numerics.inumber-1?view=net-7.0
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论