接口实现覆盖等

发布于 2024-09-26 18:20:38 字数 588 浏览 3 评论 0原文

这是我的问题的最简单形式:

IApple 需要属性 Flavor 等 IToffeeApple 还需要属性 Flavor

问题是,我希望 IToffeeApple 实现 IApple (公共接口 IToffeeApple : IApple),但它们都有相同的属性要求。当出于一个目的我需要一个糖果集合(仅限 IToffeeApple)时,这会成为一个问题,其中 IToffeeApple 也可以被识别为 IApple。

是否可以在我的界面中使用“new”关键字,以便任何实现者都拥有 2 个 Flavor 属性?

我对自己的解释很糟糕吗? :\

编辑:我有。实际上下文是几何图形:

  • ILine 需要起点和终点 IPoint。
  • ICurve 需要起点和终点 IControlPoint。

ICurve 只是 ILine 之上的额外功能,但这意味着我想将 Start 和 End 作为 IControlPoint 而不是 IPoint 返回,因此我要么实现两者并返回 IControPoint 和 IPoint of Start 和 End,要么我忽略IPoint/ILine 并将 DRY 扔出窗外。

Here's the simplest form of my question:

IApple requires, among other things, property Flavor
IToffeeApple also requires property Flavor

The problem is, I want IToffeeApple to implement IApple (public interface IToffeeApple : IApple), but they both have the same property requirement. This becomes a problem when, for 1 purpose I need a Collection of Sweets (only IToffeeApple) where IToffeeApple can also be recognised as IApple.

Is it ok to use the "new" keyword in my interface, so that any implementers have 2 Flavor properties?

Have I explained myself poorly? :\

edit: I have. The actual context is geometry:

  • ILine requires a Start and End point IPoint.
  • ICurve requires a Start and End point IControlPoint.

ICurve is just extra functionality on top of ILine, yet it means I want to return the Start and End as IControlPoint rather than IPoint, so I either implement both and have a return of both IControPoint and IPoint of Start and End, or I just ignore IPoint/ILine and throw DRY out the window.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萌无敌 2024-10-03 18:20:38

这是 David Culp 答案的详细阐述。它很长,所以我不会作为评论发布。

虽然通用接口 IList 看起来是一个很好的解决方案,但我建议进一步详细说明语义。此外,建议考虑引入某些接口的通用和非通用版本(例如 IEnumerable 加上 IEnumerable)。

在您澄清的示例中,您应该引入一个术语来描述具有起点和终点的有限实体。一般来说,曲线不是直线,但直线是曲线。但是,由于您的曲线使用 ControlPoint 来描述其起点和终点,而线条使用普通的 Point 来代替,因此在您的特定情况下,线条不是< /strong> 一条曲线。相反,直线和曲线都类似于形状

// this interface will denote any shape that has a starting and ending point
public interface IShape
{
    IPoint Start { get; set; }
    IPoint End { get; set; }
}

// this interface will allow for specialization of staring end ending points' type
public interface IShape<TPoint> : IShape
{
    // note 'new' will be required here most probably, I didn't compile it
    TPoint Start { get; set; }
    TPoint End { get; set; }
}

// a line will be a shape descibed by a pair of points; for the sake of 
public interface ILine : IShape<Point> { }

// a curve will be a shape described by a pair of control points
public interface ICurve : IShape<ControlPoint> { }

然后,ILineICurve 的实际实现可以使用来自以下属性的 StartEnd 属性的显式实现:非通用 IShape 接口。这将有利于对定界点的强类型访问,同时保留像使用普通 IShape 一样使用它们的能力。

 public class Curve : ICurve 
 {
     public ControlPoint Start { get; set; }
     public ControlPoint End { get; set; }
     IShape.Start 
     {
         get { return Start; }
         set 
         {
              if (!(value is ControlPoint)) ... some error handling ...; 
              Start = (ControlPoint)value; 
         }
     }
     IShape.End { ... similarly as IShape.Start ... }
 }

 public class Line : ILine { ... similarly as Curve ... }

请注意,对于上面显示的可能的错误情况,改进可能是将 IShape 的属性仅限于 getter。或者,将 value 传递到 StartEnd 的强类型版本的 setter 可以将点转换为控件观点。当然,正确的解决方案是针对特定领域的。

This is an elaboration of David Culp's answer. It's quite long, so I'm not posting as a comment.

While the generic interface IList<TPoint> looks like a good solution, I would recommend to elaborate the semantics a bit further. Also, it's advisory to consider introducing both generic and non-generic versions of some interface (like IEnumerable plus IEnumerable<T>).

In your clarified example you should introduce a term describing a finite entity that has a starting and ending point. Generally a curve is not a line but a line is a curve. However, since your curve uses ControlPoints to describe its start and end, while the line uses plain Points instead, in your specific case a line is not a curve. Instead, both line and curve are something like a shape.

// this interface will denote any shape that has a starting and ending point
public interface IShape
{
    IPoint Start { get; set; }
    IPoint End { get; set; }
}

// this interface will allow for specialization of staring end ending points' type
public interface IShape<TPoint> : IShape
{
    // note 'new' will be required here most probably, I didn't compile it
    TPoint Start { get; set; }
    TPoint End { get; set; }
}

// a line will be a shape descibed by a pair of points; for the sake of 
public interface ILine : IShape<Point> { }

// a curve will be a shape described by a pair of control points
public interface ICurve : IShape<ControlPoint> { }

Then, the actual implementations of ILine and ICurve can use explicit implementations of the Start and End properties coming from the non-generic IShape interface. This will favor strongly-typed access to the delimiting points, while preserving the ability to work with them as with plain IShapes.

 public class Curve : ICurve 
 {
     public ControlPoint Start { get; set; }
     public ControlPoint End { get; set; }
     IShape.Start 
     {
         get { return Start; }
         set 
         {
              if (!(value is ControlPoint)) ... some error handling ...; 
              Start = (ControlPoint)value; 
         }
     }
     IShape.End { ... similarly as IShape.Start ... }
 }

 public class Line : ILine { ... similarly as Curve ... }

Note that in respect to the possible error scenario shown above an improvement could be limiting IShapes properties to getters only. Or, the setter passing the value into the strongly-typed version of Start or End could do some kind of conversion of a point into a control point. The right solution is domain-specific of course.

飘过的浮云 2024-10-03 18:20:38

尝试以下方法:

interface IFlavor;
interface ISweets: IFlavor;
interface IApple: IFlavor;
interface IToffeeApple: IApple, ISweets;

IEnumerable 可以容纳 IToffeeApple,但不能容纳 IApple。

当似乎需要“替换”继承的属性以使继承有意义时,我通常会寻找以下两件事之一。要么继承是强制的(汽车和苹果都有颜色,但通常不被认为是多态的),要么继承比乍一看更深。

如果我对这个例子理解得足够好,那么更深层次的继承就足够合适了。


为了适合您的新示例:

public interface IPoint
{}

public interface IControlPoint : IPoint
{
    // added functionality of IControlPoint
}

public interface ILine<TPoint>
    where TPoint : IPoint
{
    TPoint Start { get; set; }
    TPoint End { get; set; }
}

public interface ICurve<TPoint> : ILine<TPoint>
    where TPoint : IPoint
{
    // added functionality of ICurve
}

我假设 IControlPoint 实现 IPoint,但这似乎是合理的。

基本上,泛型负责需要 IControlPoint 才能使用的 ICurve,而 ILine 则需要 IPoint

Try something along the lines of:

interface IFlavor;
interface ISweets: IFlavor;
interface IApple: IFlavor;
interface IToffeeApple: IApple, ISweets;

IEnumerable<ISweets> can hold the IToffeeApple, but not IApple.

When there seems to be a need to 'replace' an inherited property for the inheritance make sense I generally look for one of two things. Either the inheritance is forced (a car and an apple both have a color, but are not often thought of as polymorphic), or the inheritance is deeper than it seemed at first glance.

If I understand the example well enough, deeper inheritance fits well enough.


To fit your new example:

public interface IPoint
{}

public interface IControlPoint : IPoint
{
    // added functionality of IControlPoint
}

public interface ILine<TPoint>
    where TPoint : IPoint
{
    TPoint Start { get; set; }
    TPoint End { get; set; }
}

public interface ICurve<TPoint> : ILine<TPoint>
    where TPoint : IPoint
{
    // added functionality of ICurve
}

I am making the assumption that IControlPoint implements IPoint, but it seemed reasonable.

Basically, generics takes care of ICurve needing an IControlPoint to work with, while ILine needs an IPoint.

橘虞初梦 2024-10-03 18:20:38

不,您不需要 new 关键字来从另一个接口中的一个接口继承属性:

public interface IApple
{
    Flavor Flavor { get; }
}

public interface IToffeeApple : IApple
{
    ICollection<Sweet> Sweets { get; }
}

public class MyToffeeApple : IToffeeApple
{
    public Flavor Flavor { get { return Flavors.ToffeeFlavor; } }
    public ICollection<Sweet> Sweets { get { return new Sweet[0]; } }
}

工作得很好。如果这不能回答您的问题,请编辑问题以包含详细信息,以解释上述内容的不足之处。

No, you don’t need the new keyword to inherit a property from an interface in another interface:

public interface IApple
{
    Flavor Flavor { get; }
}

public interface IToffeeApple : IApple
{
    ICollection<Sweet> Sweets { get; }
}

public class MyToffeeApple : IToffeeApple
{
    public Flavor Flavor { get { return Flavors.ToffeeFlavor; } }
    public ICollection<Sweet> Sweets { get { return new Sweet[0]; } }
}

Works just fine. If this doesn’t answer your question, please edit the question to include detail that explains in what way the above is insufficient.

草莓酥 2024-10-03 18:20:38

不,因为 IToffeeApple 只是继承自 IApple(它没有实现任何东西,它只是一个接口)并且不存在冲突;只需保留 Flavor 属性,这样它就会从 IApple 继承它。

这不会成为仅具有 IToffeeApple 的集合的属性,因为那里也不会有任何冲突的情况。

只有当某种东西既实现了 IToffeeApple 又实现了风味具有不同类型的其他东西,或者风味具有不同含义的 IQuark 时,它才可能真正成为问题。在这种情况下,实现它们的类应该显式实现这两个属性或这两个属性。

No, because IToffeeApple is only inheriting from IApple (it isn't implementing anything, it's an interface) and there's no conflict; just leave the Flavour property out so it inherits it from IApple.

This doesn't becomes a property with a collection that only has IToffeeApple, because there won't be any conflicting cases there either.

It could only really become a problem if something implemented both IToffeeApple, and either something else where flavour had a different type, or IQuark where flavour has a different meaning. In this case the class implementing them should implement on or both of the properties explicitly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文