У меня возник такой вопрос. Допустим, в методе set некоторого свойства ссылочного типа я хочу наложить определенные ограничения на входящие значения value, например:
class MyRefClass
{
public int SomeNumber;
}
class MyTestClass
{
private MyRefClass _myRefClass;
public MyRefClass MyProperty
{
get
{
return _myRefClass;
}
set
{
if (value.SomeNumber < 0)
{
throw new SomeException();
}
_myRefClass = value;
}
}
}
Но, получив текущее значение с помощью get, я могу изменить состояние свойства, минуя set и, соотвественно, заложенную в него логику.
Как поступать в таких ситуациях? Может в set необходимо value проверять только на null?
Здравствуйте, dorofeevilya, Вы писали:
D>Как поступать в таких ситуациях? Может в set необходимо value проверять только на null?
сделать MyRefClass immutable.
Здравствуйте, SiAVoL, Вы писали:
SAV>сделать MyRefClass immutable.
Если вы про ImmutableObjectAttribute, то это совершенно мне не подходит. Во-первых, атрибут относится к компонентной модели, которой я не пользуюсь, а, во-вторых, "...this property is used only at design time." (хотя это является следствием первой причины).
Поясните, пожалуйста, если я вас неправильно понял. Спасибо.
Здравствуйте, dorofeevilya, Вы писали:
D>У меня возник такой вопрос. Допустим, в методе set некоторого свойства ссылочного типа я хочу наложить определенные ограничения на входящие значения value, например:
… D>Но, получив текущее значение с помощью get, я могу изменить состояние свойства, минуя set и, соотвественно, заложенную в него логику. D>Как поступать в таких ситуациях?
Сначала подумать, а нельзя ли сделать MyRefClass неизменяемым (immutable). Если не удаётся, думаем дальше :о)
Представим себе такую ситуацию:
var c = new MyRefClass { SomeNumber = 1, };
var t = new MyTestClass { MyProperty = c, };
c.SomeNumber = -1; // *
Что должно произойти в (*)? В каком месте должно возникнуть исключение и почему? В MyTestClass? Но формально-то эта строчка никакого отношения к нему не имеет!
Можно попробовать сделать такую логику: в MyRefClass хранить признак того, что значение свойства не должно быть отрицательным.
Второй вариант — рассылать из MyRefClass события SomeNumberChanging\SomeNumberChanged и подписаться на первое в MyTestClass.MyProperty.set, проверять логику и бросать исключение.
... << RSDN@Home 1 alpha 3 rev. 0>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, dorofeevilya, Вы писали:
D>Если вы про ImmutableObjectAttribute, то это совершенно мне не подходит. Во-первых, атрибут относится к компонентной модели, которой я не пользуюсь, а, во-вторых, "...this property is used only at design time." (хотя это является следствием первой причины).
D>Поясните, пожалуйста, если я вас неправильно понял.
ImmutableObjectAttribute тут непричём. Речь о неизменяемых типах. Примером такого типа является Sysem.String и System.Version. Смысл в том, что невозможно изменить значение полей объекта после его создания.
... << RSDN@Home 1 alpha 3 rev. 0>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, dorofeevilya, Вы писали:
_FR>Сначала подумать, а нельзя ли сделать MyRefClass неизменяемым (immutable). Если не удаётся, думаем дальше :о)
SiAVoL тоже писал про immutable, но я не очень понимаю, что это, и как так сделать
_FR>Представим себе такую ситуацию: _FR>
_FR>var c = new MyRefClass { SomeNumber = 1, };
_FR>var t = new MyTestClass { MyProperty = c, };
_FR>c.SomeNumber = -1; // *
_FR>
_FR>Что должно произойти в (*)? В каком месте должно возникнуть исключение и почему? В MyTestClass? Но формально-то эта строчка никакого отношения к нему не имеет!
В принципе, согласен. Но и допустить изменения значения нельзя. Иначе MyTestClass t перейдет в invalid state.
_FR>Можно попробовать сделать такую логику: в MyRefClass хранить признак того, что значение свойства не должно быть отрицательным.
Нет, это не подойдет. Пример, который я привел, абстрактный. В реальности в MyTestClass может быть одна логика, в MyTestClass1 — другая, в MyTestClass2 — третья (в том числе и просто: set { _myProperty = value; } без всяких проверок ) и т. д.
_FR>Второй вариант — рассылать из MyRefClass события SomeNumberChanging\SomeNumberChanged и подписаться на первое в MyTestClass.MyProperty.set, проверять логику и бросать исключение.
Я тоже об этом думал. Но боюсь, что вся программа таким образом будет построена на событиях. Мне кажется, что в данном случае события не совсем подходят.
Может быть у меня не совсем верное архитектурное решение?
Здравствуйте, dorofeevilya, Вы писали:
_FR>>Сначала подумать, а нельзя ли сделать MyRefClass неизменяемым (immutable). Если не удаётся, думаем дальше :о) D> SiAVoL тоже писал про immutable, но я не очень понимаю, что это, и как так сделать
Начать с того, что объявить все поля объекта как readonly.
_FR>>Что должно произойти в (*)? В каком месте должно возникнуть исключение и почему? В MyTestClass? Но формально-то эта строчка никакого отношения к нему не имеет! D>В принципе, согласен. Но и допустить изменения значения нельзя. Иначе MyTestClass t перейдет в invalid state.
Тогда надо ожслеживать.
_FR>>Можно попробовать сделать такую логику: в MyRefClass хранить признак того, что значение свойства не должно быть отрицательным. D>Нет, это не подойдет. Пример, который я привел, абстрактный. В реальности в MyTestClass может быть одна логика, в MyTestClass1 — другая, в MyTestClass2 — третья (в том числе и просто: set { _myProperty = value; } без всяких проверок ) и т. д.
Например, проверки\валидаторы можно внедрять как стратегии.
_FR>>Второй вариант — рассылать из MyRefClass события SomeNumberChanging\SomeNumberChanged и подписаться на первое в MyTestClass.MyProperty.set, проверять логику и бросать исключение. D>Я тоже об этом думал. Но боюсь, что вся программа таким образом будет построена на событиях. Мне кажется, что в данном случае события не совсем подходят.
Не понятно — почему? Что значит "вся программа таким образом будет построена на событиях"?
D>Может быть у меня не совсем верное архитектурное решение?
Надо его, решение, для начала описать :о) Пока не понятна конечная цель, не известны средства — какие компоненты можно и как менять, а какие нет. Не понятно и с ограничениями.
... << RSDN@Home 1 alpha 3 rev. 0>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>ImmutableObjectAttribute тут непричём. Речь о неизменяемых типах. Примером такого типа является Sysem.String и System.Version. Смысл в том, что невозможно изменить значение полей объекта после его создания.
Аааа! Понял. Но дело в том, что объекты класса MyRefClass точно не могут быть immutable.
А если от MyRefClass наследовать специфичный класс для использования в качестве типа свойства MyProperty в MyTestClass:
class MyRefClass
{
private int _someNumber;
public virtual int SomeNumber
{
get { return _someNumber; }
set { _someNumber = value; }
}
}
class MyNonNegativeRefClass : MyRefClass
{
public override int SomeNumber
{
get { return base.SomeNumber; }
set { if (value < 0) { throw new SomeException(); } else base.SomeNumber = value; }
}
}
class MyTestClass
{
private MyNonNegativeRefClass _myRefClass;
public MyRefClass MyProperty
{
get
{
return _myRefClass;
}
set
{
if (value == null)
{
throw new ArgumentNullException();
}
_myRefClass = value;
}
}
}
Здравствуйте, dorofeevilya, Вы писали:
D>А если от MyRefClass наследовать специфичный класс для использования в качестве типа свойства MyProperty в MyTestClass:
В выделенном месте необходимо приведение типов, то есть надо определить, на каком уровне известно про MyNonNegativeRefClass. И что должно происходить в таком случае:
var c = new MyRefClass { SomeProperty = -1, };
var t = new MyTestClass { MyProperty = c, };
... << RSDN@Home 1 alpha 3 rev. 0>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>В выделенном месте необходимо приведение типов, то есть надо определить, на каком уровне известно про MyNonNegativeRefClass.
Оппа-па! Я извиняюсь. Не заметил, когда правил сообщение. Конечно же, вполне устраивает:
class MyTestClass
{
public MyNonNegativeRefClass MyProperty { ... }
}
Здравствуйте, dorofeevilya, Вы писали:
_FR>>В выделенном месте необходимо приведение типов, то есть надо определить, на каком уровне известно про MyNonNegativeRefClass.
D>Оппа-па! Я извиняюсь. Не заметил, когда правил сообщение. Конечно же, вполне устраивает: D>Т. е. никаких приведений типов.
Тогда неплохо, я бы только посоветовал в реализации MyRefClass\MyNonNegativeRefClass использовать Non-virtual interface