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

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

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

Тем не менее, мне было интересно, почему следующее является незаконным с явным объявлением интерфейса и юридическим с неявным:

interface IConnection
{
    string ConnectionString { get; }
}

class Connection1 : IConnection
{
    // private set is illegal, won't compile
    string IConnection.ConnectionString { get; private set; }
}

class Connection2 : IConnection
{
    // private set is legal now, it is not part of the interface
    string ConnectionString { get; private set; }
}

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

Тем не менее, мне интересно, почему это объясняется. Поскольку технически, внутренне скомпилированный частный метод set_IConnection_ConnectionString не обязательно должен быть частью интерфейса, не так ли? Его можно просто рассматривать как вспомогательный сеттер, а не часть интерфейса, как это происходит в неявной ситуации реализации.

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

Модификатор доступности для доступа должен быть более строгим, чем свойство Connection1.ConnectionString

Извините, более ограничительный, чем private, как... что?

4b9b3361

Ответ 1

Единственный способ вызвать явного члена интерфейса - передать объект в правильный интерфейс, а затем вызвать элемент на этом интерфейсе. Но как только вы набрали IConnection, IConnection.ConnectionString не имеет сеттера.

Таким образом, нет способа вызвать этот частный метод setter.

Ответ 2

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

В принципе, когда говорят void IFoo.Moo(), говорят, что не нужно определять имя Moo в пределах класса; следовательно, компилятор не будет. Для того, чтобы private set работал, член должен был быть "объявляемым" именем, а тот факт, что элемент был явно реализован, воспринимается как признак того, что имя не должно быть Moo.

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

private readonly int _foo = whatever;
public int IFOO.Foo { get {return _foo;}}

или, если производные классы должны иметь возможность воздействовать на него, либо

protected int _foo = whatever;
public int IFOO.Foo { get {return _foo;}}

или

private int _foo = whatever;
protected virtual int setFoo(int value) { _foo = value; }
protected virtual int getFoo() { return _foo; }
public int IFOO.Foo { get {return getFoo();}}

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

Ответ 3

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

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

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

Ответ 4

Объявление свойства - это атомная вещь, содержащая геттер и сеттер. Он должен соответствовать интерфейсу.

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

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

Ответ 5

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

public interface I {
    string S { get; set; }
}

class C : I {
    public C() {
        this.S = "Hello World"; 
        //compile error: explicit implementation not accessible
    }

    string I.S { get; set; }
}

В классе C свойство S даже не является частным образом доступным, поскольку оно является явной реализацией. Не будет ли плохой дизайн в первую очередь для того, чтобы конкретная реализация поля не была доступна самой реализации?

Кроме того, в вашем примере создание сеттера для явного импликации никогда не будет доступно; поскольку свойство доступно только при передаче в интерфейс IConnection. Там он имеет только приемник.