这是我最简单的问题形式:
IApple除其他外还要求财产Flavor IToffeeApple还需要属性Flavor
问题是,我希望IToffeeApple实现IApple(公共接口IToffeeApple:IApple),但它们都具有相同的属性要求。如果出于一个目的,我需要一个糖果集合(仅限IToffeeApple),其中IToffeeApple也可以被识别为IApple,这就成了一个问题。
在我的界面中使用“new”关键字是否可以,以便任何实施者都有2个Flavor属性?
我解释得不好吗? :\
编辑:我有。实际的上下文是几何:ICurve只是ILine之上的额外功能,但它意味着我想将Start和End作为IControlPoint而不是IPoint返回,所以我要么实现两者,要么返回IControPoint和开始和结束的IPoint,或者我只是忽略IPoint / ILine并将DRY抛出窗口。
答案 0 :(得分:3)
尝试以下方面的内容:
interface IFlavor; interface ISweets: IFlavor; interface IApple: IFlavor; interface IToffeeApple: IApple, ISweets;
IEnumerable<ISweets>
可以保留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
,但这似乎是合理的。
基本上,泛型需要ICurve
需要IControlPoint
才能使用,而ILine
则需要IPoint
。
答案 1 :(得分:3)
这是David Culp答案的详细阐述。这很长,所以我不会发表评论。
虽然通用接口IList<TPoint>
看起来是一个很好的解决方案,但我建议进一步详细说明语义。此外,建议考虑引入某些界面的通用和非通用版本(例如IEnumerable
加IEnumerable<T>
)。
在您的澄清示例中,您应该引入一个术语来描述具有起点和终点的有限实体。通常,曲线不是直线而是直线是曲线。但是,由于曲线使用ControlPoint
来描述其开始和结束,而线条使用普通Point
代替,在您的特定情况下,线不是曲线。相反,线条和曲线都类似于形状。
// 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> { }
然后,ILine
和ICurve
的实际实现可以使用来自非通用Start
接口的End
和IShape
属性的显式实现。这将有利于对分隔点进行强类型访问,同时保留与普通IShape
s一样使用它们的能力。
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
传递到Start
或End
的强类型版本的setter可以将某个点转换为控制点。当然,正确的解决方案是针对特定领域的。
答案 2 :(得分:1)
不,您不需要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]; } }
}
工作得很好。如果这不能回答您的问题,请编辑问题以包含解释上述内容不足的详细信息。
答案 3 :(得分:0)
不,因为IToffeeApple只是继承自IApple(它没有实现任何东西,它是一个接口)并且没有冲突;只需保留Flavor属性,以便从IApple继承它。
这不会成为一个只有IToffeeApple的集合的属性,因为那里也不存在任何冲突的情况。
如果IToffeeApple同时实现了某些东西,或者其他类型的东西都有不同的类型,或者味道具有不同含义的IQuark,那么它真的会成为一个问题。在这种情况下,实现它们的类应该明确地实现一个或两个属性。