Абстрактные свойства C#, ошибка или особенность?

249
08 марта 2017, 16:53

Исходные условия:

interface ISomeInterface
{
    int SomeProperty { get; }
}
abstract class SomeClass
{
    public abstract int AnotherProperty { get; }
}
class InheritedClass : SomeClass, ISomeInterface
{
    public int SomeProperty { get; set; }
    public override int AnotherProperty  { get; set; }//Ошибка
}

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

Answer 1

С точки зрения интерфейсов, все правильно. Свойство представляет из себя пару методов. В интерфейсе, мы обязываем класс, реализующий наш интерфейс реализовать свойство с указанным аксессором, при этом не накладывая ни каких условий на наличие либо отсутствие второго аксессора.

С абстрактным классом немного сложнее. При реализации абстрактного свойства мы обязаны указать перед таким свойством ключевое слово override, указывающее компилятору, что свойство было объявлено в базовом классе.

Синтаксис не позволяет указать override для одного конкретного аксессора, а только для всего свойства целиком, поэтому необъявленый в базовом классе аксессор, тоже получает метку override, но переопределить его нельзя, так как он отсутствует в базовом классе.

Таким образом имеем противоречие: с одной стороны, мы пытаемся добавить новый метод в класс наследник, что не должно вызывать каких либо проблем, с другой, следуя синтаксису языка, пытаемся переопределить несуществующий метод, что вполне закономерно вызывает ошибку компиляции.

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

Как обойти проблему

Одно из возможных решений обхода данной "особенности":

abstract class SomeClass
{
    public int AnotherProperty 
    { 
        get { return GetAnotherProperty(); }  
    }
    protected abstract int GetAnotherProperty();
}
class InheritedClass : SomeClass
{
    public new int AnotherProperty  { get; set; }
    protected override int GetAnotherProperty() 
    { 
        return AnotherProperty; 
    }
}

Другой вариант - вынести свойство в отдельный интерфейс и реализовать его в производном классе, тогда проблема решается вроде бы сама собой, но иногда такое решение не приемлемо, например если в абстрактном классе есть реализованные методы использующие данное свойство.

Ну и радикальный вариант - отказ от свойства как такового, и возврат к классическим методам GetXXX() и SetXXX(value), этот вариант возможен абсолютно в любых условиях и не вызывает проблем ни в интерфейсах, ни в абстрактных классах, но ухудшает читабельность кода, хотя это конечно на любителя, в Java например, это единственный возможный вариант, если за последнее время в ней ни чего кардинально не поменялось.

READ ALSO
WPF. Команды в Datacontext

WPF. Команды в Datacontext

Есть viewmodel

294
Редактирование модели. Ошибка. The model item passed into the dictionary is of type 'System.Data.Entity.DbSet`1[justfortest.Models.Book]'

Редактирование модели. Ошибка. The model item passed into the dictionary is of type 'System.Data.Entity.DbSet`1[justfortest.Models.Book]'

Пытаюсь создать редактирование моделиВыскакивает ошибка:

292
Как в с# парсить куки созданные в javaScript?

Как в с# парсить куки созданные в javaScript?

Собственно вопрос заданЧасто на сайтах некоторые куки задаются не через Response, динамически при отработке javaScript

233
Сессии пользователя на php

Сессии пользователя на php

Пишу аторизацию пользователя через вк

283