Подтвердить что ты не робот

Добавление сеттеров к свойствам в переопределениях

Почему разрешено изменять видимость и существование геттеров или сеттеров в свойстве при реализации интерфейса?

interface IFoo
{
    string Bar { get; }
}

class RealFoo : IFoo
{
    public RealFoo(string bar)
    {
        this.Bar = bar;
    }

    public string Bar { get; private set; }
}

class StubFoo : IFoo
{
    public string Bar { get; set; }
}

... и не законно делать то же самое при реализации абстрактного класса?

abstract class AbstractFoo : IFoo
{
    public abstract string Bar { get; }
}

class RealFoo : AbstractFoo
{
    public RealFoo(string bar)
    {
        this.Bar = bar;
    }

    // Cannot override because 'Bar' does not have an overridable set accessor
    public override string Bar { get; private set; }
}
4b9b3361

Ответ 1

Интерфейс объявляет, какие общедоступные свойства должен иметь класс (это просто контракт). Это означает, что вам нужно иметь эти свойства, но можете добавить к ним.

Абстрактный класс объявляет фактическую структуру этих свойств. Поэтому, если у вас нет установщика в абстрактной базе, вы не можете добавить к нему в реализацию.
Когда вы пишете модификатор переопределения, он выглядит в базовом классе, чтобы что-то переопределить.

Ответ 2

Возможно, станет понятнее, если вы думаете о геттерах и сеттерах как о методах, которые они в конечном итоге становятся.

В случае интерфейса вы определяете это:

interface IFoo
{
    string GetBar();
}

Что можно прочитать как "все классы, реализующие этот интерфейс, должны включать этот метод". Оба ваших класса:

class RealFoo : IFoo
{
    public string GetBar();
    private void SetBar(string value);
}

они также реализуют SetBar(), но это несущественно; они выполнили контракт, определенный интерфейсом и действительны.

С другой стороны, абстрактный класс:

abstract class AbstractFoo : IFoo
{
    public abstract string GetBar();
}

Это означает, что все дочерние классы должны предоставить тело метода для GetBar()

Вы создали этот класс:

class RealFoo : AbstractFoo
{
    public override string GetBar();
    public override void SetBar(string value);
}

Поместив модификатор переопределения перед методом SetBar, компилятор ожидает найти абстрактную или виртуальную версию в базовом классе. У вас этого нет, поэтому компиляция не удалась.

Ответ 3

Абстрактный класс - это класс, который не может быть создан, но должен быть унаследован. Абстрактный класс может быть полностью реализован, но, как правило, частично реализуется или вообще не реализуется, тем самым инкапсулируя общую функциональность для унаследованных классов.

Интерфейс, напротив, представляет собой полностью абстрактный набор членов, который можно рассматривать как определение контракта на поведение. Реализация интерфейса полностью оставлена ​​разработчиком.

Взято из MSDN http://msdn.microsoft.com/en-us/library/scsyfw1d(v=VS.71).aspx

Ответ 4

В соответствии со спецификацией С#

Аксессор, который используется для реализации интерфейс может не иметь аксессор-модификатор. Если только один аксессор используется для реализации интерфейс, другой аксессуар может быть объявлено с помощью модификатора-модификатора:

public interface I
{
  string Prop { get; }
}
public class C: I
{
  public Prop {
  get { return "April"; }     // Must not have a modifier here
        internal set {...}    // Ok, because I.Prop has no set accessor
  }
}

Это означает, что он имеет право на изменение доступа к классу, реализующему интерфейс. Тем не менее, абстрактный класс объявляет реализацию, и вы не можете изменить это с производным классом.