Как мне сделать наследуемое неизменяемое свойство изменяемым в C #? - PullRequest
1 голос
/ 16 января 2012

Учтите, что у меня есть интерфейс, который содержит следующее свойство

interface IFoo
{
    Int32 Id { get; }
}

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

interface IMutableFoo: IFoo
{
    Int32 Id { set; }
}

Я думал, что он унаследует Id, и тогда в моем дочернем интерфейсе я сделаю его настраиваемым.К моему удивлению, это не сработало.Вместо этого я получаю предупреждение, сообщающее, что я на самом деле переопределяю Id в IFoo с Id в IMutableFoo.Я пытался изменить {установить;} получить;задавать;} с теми же результатами.Как мне сделать это правильно?В Java я бы просто добавил метод setId.Как мне это сделать в C #?Спасибо!

Ответы [ 4 ]

4 голосов
/ 16 января 2012

Вы ничего не можете сделать, кроме определения нового интерфейса с новым свойством чтения / записи.Это потому, что нет понятия наследования, когда речь идет об интерфейсах;скорее интерфейс, такой как IMutableFoo, обещает, что его разработчики также будут реализовывать интерфейс IFoo.Оба интерфейса, однако, были определены независимо и остаются независимыми.

Документация MSDN содержит фразу "интерфейсы могут наследовать другие интерфейсы" , но это ИМХО вводит в заблуждение, посколькуздесь нет наследства.«Производный» интерфейс просто описывает больший набор элементов, которые должны быть реализованы, чем «базовый» интерфейс.

Реализаторы интерфейса, такие как IMutableFoo, могут предоставить семантику, на которую вы нацелены, без проблем, явнореализация IFoo и совместное использование кода между получателями IMutableFoo.Id и IFoo.Id:

class Foo : IMutableFoo {
    // IFoo is implemented explicitly
    // "this" is of type Foo, and since IMutableFoo is implemented
    // implicitly below, this.Id accesses the Id declared in IMutableFoo
    Int32 IFoo.Id { get { return this.Id; } }

    // IMutableFoo is implemented implicitly
    // It could also be implemented explicitly, but the body of the
    // IFoo.Id getter would need to change ("this" would no longer work)
    public Int32 Id { get; set; }
}

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

2 голосов
/ 16 января 2012

Повторное объявление Id в интерфейсе потомка действительно скрывает тот, что в родительском.

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

1- Использование абстрактного или даже неабстрактного класса вместо изменяемого интерфейса.

interface IFoo {
    Int32 Id { get; }
}
abstract class MutableFoo: IFoo {
    public abstract Int32 Id {get; set;}
}

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

2 - Использование метода вместо свойства.

interface IFoo {
    Int32 Id { get; }
}
interface IMutableFoo: IFoo {
    void SetId(Int32 value);
}

Это не идеально, потому что установщик не идиоматичен и выглядит отсоединенным от получателя.

1 голос
/ 16 января 2012

вы можете сделать

  public interface IFoo
    {
        Int32 Id { get; }
    }

   public interface IFooMu : IFoo
    {
        new Int32 Id { get; set; }
    }  

    class Foo : IFooMu
    {
        public Int32 Id { get; set; }
    }
0 голосов
/ 16 января 2012

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

Ваш вопрос, по-видимому, заключается в том, как сделать так, чтобы объект поддерживал чтение и чтение.только и читать-писать интерфейсы разумным способом;Ответ Кита Николаса иллюстрирует правильный метод.Обратите внимание, что если кто-то использует явную реализацию интерфейса или если он записывает класс в vb.net, а не в c #, необходимо иметь отдельные реализации как IFooMu.Id, так и IFoo.Id;это раздражающее требование, налагаемое .net, но c # допускает одно открытое свойство в качестве неявного определения для свойств только для чтения, чтения и записи и только для записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...