Добавление сеттера к производному интерфейсу
Возможно ли как-то добиться такого поведения в С#:
public interface IReadOnly
{
Data Value { get; }
}
internal interface IWritable : IReadOnly
{
Data Value { get; set; }
}
Я хочу, чтобы иметь возможность открывать интерфейс для чтения для внешних сборок, но использовать встроенный для записи интерфейс (который я также мог бы реализовать по-разному).
Я знаю, что могу использовать абстрактный класс, который реализует IReadOnly
, но добавляет сеттеры, но это заставляет меня выводить все внутренние реализации из этого класса.
Ответы
Ответ 1
Это не проблема:
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));
Ответ 2
По общему признанию, копирование, но я предпочитаю делать следующее:
public interface IReadOnly
{
Data Value { get; }
}
internal interface IWritable : IReadOnly
{
void SetValue(Data value);
}
В то время как ответ Hans Passant работает, я нахожу, что это раздражает то, что с определенными деревьями наследования код с использованием интерфейса потомка может по-прежнему жалуяться, что он не знает, к какой версии "значения" вы обращаетесь - даже с установщиком!
Ответ 3
Ханс Пассант дал очень хороший ответ, и я пришел к аналогичному ответу, но я думаю, что смогу сделать лучше:
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 efined M odel.
Ответ 4
Чтобы это было хорошо, нужно объявить и реализовать IReadWrite, который наследует как IReadable, так и IWritable, и включает в себя "новое" свойство read-write. В противном случае интерфейс, который имеет отдельные свойства get и set, но не имеет свойства get-set, не будет доступен для чтения и записи.