Переопределение реализации интерфейса и т. Д. - PullRequest
0 голосов
/ 08 октября 2010

Вот самая простая форма моего вопроса:

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 из Start и End, или Я просто игнорирую IPoint / ILine и выбрасываю DRY в окно.

Ответы [ 4 ]

3 голосов
/ 09 октября 2010

Это развитие ответа Дэвида Калпа. Это довольно долго, поэтому я не публикую в качестве комментария.

Хотя общий интерфейс IList<TPoint> выглядит хорошим решением, я бы порекомендовал немного проработать семантику. Кроме того, рекомендуется рассмотреть возможность использования как общих, так и неуниверсальных версий некоторых интерфейсов (например, IEnumerable plus IEnumerable<T>).

В вашем поясненном примере вы должны ввести термин, описывающий конечную сущность, которая имеет начальную и конечную точку. Обычно кривая - это не линия, а линия - это кривая. Однако, поскольку ваша кривая использует ControlPoint s для описания ее начала и конца, в то время как линия вместо этого использует простые Point s, в вашем конкретном случае линия не является кривой. Вместо этого и линия, и кривая представляют собой нечто вроде 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> { }

Тогда фактические реализации ILine и ICurve могут использовать явные реализации свойств Start и End, поступающие из неуниверсального интерфейса 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 только для получателей. Или установщик, передающий value в строго типизированную версию Start или End, может выполнить какое-то преобразование точки в контрольную точку. Разумеется, правильное решение зависит от конкретной области.

3 голосов
/ 08 октября 2010

Попробуйте что-то вроде:

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 голос
/ 08 октября 2010

Нет, вам не нужно ключевое слово 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]; } }
}

Работает просто отлично.Если это не отвечает на ваш вопрос, отредактируйте вопрос, включив в него подробности, объясняющие, почему вышеприведенного недостаточно.

0 голосов
/ 08 октября 2010

Нет, потому что IToffeeApple наследуется только от IApple (он ничего не реализует, это интерфейс) и конфликта нет; просто не указывайте свойство Flavor, чтобы оно наследовало его от IApple.

Это не становится свойством для коллекции, в которой есть только IToffeeApple, потому что там не будет конфликтующих случаев.

Это могло бы действительно стать проблемой, если бы что-то реализовывало и IToffeeApple, и что-то еще, где аромат имел другой тип, или IQuark, где аромат имел другое значение. В этом случае реализующий их класс должен реализовать одно или оба свойства явно.

...