Добавление сеттера в производный интерфейс - PullRequest
32 голосов
/ 19 июля 2011

Возможно ли как-то добиться такого поведения в C #:

public interface IReadOnly
{
    Data Value { get; }
}

internal interface IWritable : IReadOnly 
{
    Data Value { get; set; }
}

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

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

Ответы [ 4 ]

41 голосов
/ 19 июля 2011

Это не проблема:

public interface IReadOnly {
    Data Value { get; }
}

internal interface IWritable : IReadOnly {
    new Data Value { get; set; }
}

internal class Impl : IWritable {
    public Data Value { get; set; }
}

Реализация свойства Impl.Value заботится о обоих IReadOnly.Value и IWritable.Value, как показано в этом фрагменте теста:

        var obj = new Data();
        var target = new Impl();
        var irw = (IWritable)target;
        irw.Value = obj;
        var iro = (IReadOnly)target;
        System.Diagnostics.Debug.Assert(Object.ReferenceEquals(iro.Value, obj));
0 голосов
/ 01 декабря 2017

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

public interface IReadOnly
{
  Data Value { get; }
}

internal interface IWritable : IReadOnly 
{
  void SetValue(Data value);
}

Хотя ответ Ханса Пассанта работает, меня раздражает, что с некоторыми деревьями наследования код с использованием интерфейса-потомкавсе еще жалуются, что не знают, на какую версию «Value» вы ссылаетесь - даже с установщиком!

0 голосов
/ 26 октября 2013

Ханс Пассант дал очень хороший ответ, и я пришел к аналогичному ответу, но я думаю, что смогу сделать лучше:

public interface IReadOnly : IWritable
{
    new int MyValue { get; }
}

public interface IWritable
{
    int MyValue { get; set; }
}

public class Implementation : IReadOnly
{
    public int MyValue { get; private set; }

    int IWritable.MyValue
    {
        set { MyValue = value; }
        get { return MyValue; }
    }

    public static Implementation GetMyImplementation()
    {
        return ImplementationGateway<Implementation>.GetMyImplementation();
    }
}


public class ImplementationGateway<TImplementation>
    where TImplementation : class, IWritable, new()
{
    public static TImplementation GetMyImplementation()
    {
        return new TImplementation
            {
                MyValue = 1
            };
    }
}

public class Program
{
    public Program()
    {
        Implementation myImplementation = Implementation.GetMyImplementation();
        myImplementation.MyValue = 0; //This will and is supposed to fail
    }

}

Разница между моим и мистером. Решение Passant заключается в том, что мой IReadOnly наследуется от моего IWritable. В результате этого кода вы не можете установить MyValue в классе Program, который может быть таким, каким вы хотите, чтобы он работал. Извлеките и отобразите данные в вашем классе Gateway, но затем установите их в качестве значения только для чтения. С этим у вас есть разделение чтения / записи. В качестве дополнительного бонуса, единственное, что ваш DAL знает о ваших объектах, - это интерфейс, который они используют в качестве «контракта».
I nterface D определено M odel.

0 голосов
/ 19 июля 2011

Чтобы это работало хорошо, нужно объявить и реализовать IReadWrite, который наследует как IReadable, так и IWritable и включает в себя «новое» свойство чтения-записи. В противном случае интерфейс, который имеет отдельные свойства get и set, но не имеет свойства get-set, не будет ни читаемым, ни записываемым.

...