Ссылочные типы и get/set property
От: dorofeevilya Россия  
Дата: 15.07.08 08:23
Оценка:
Добрый день.

У меня возник такой вопрос. Допустим, в методе 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?
Re: Ссылочные типы и get/set property
От: SiAVoL Россия  
Дата: 15.07.08 08:44
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>Как поступать в таких ситуациях? Может в set необходимо value проверять только на null?

сделать MyRefClass immutable.
... << RSDN@Home 1.2.0 alpha 4 rev. 1096>>
Re[2]: Ссылочные типы и get/set property
От: dorofeevilya Россия  
Дата: 15.07.08 08:52
Оценка:
Здравствуйте, SiAVoL, Вы писали:

SAV>сделать MyRefClass immutable.


Если вы про ImmutableObjectAttribute, то это совершенно мне не подходит. Во-первых, атрибут относится к компонентной модели, которой я не пользуюсь, а, во-вторых, "...this property is used only at design time." (хотя это является следствием первой причины).

Поясните, пожалуйста, если я вас неправильно понял. Спасибо.
Re: Ссылочные типы и get/set property
От: _FRED_ Черногория
Дата: 15.07.08 08:53
Оценка:
Здравствуйте, 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.
Re[3]: Ссылочные типы и get/set property
От: _FRED_ Черногория
Дата: 15.07.08 09:04
Оценка:
Здравствуйте, 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.
Re[2]: Ссылочные типы и get/set property
От: dorofeevilya Россия  
Дата: 15.07.08 09:04
Оценка:
Здравствуйте, _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, проверять логику и бросать исключение.

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

Может быть у меня не совсем верное архитектурное решение?
Re[3]: Ссылочные типы и get/set property
От: _FRED_ Черногория
Дата: 15.07.08 09:09
Оценка:
Здравствуйте, 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.
Re[4]: Ссылочные типы и get/set property
От: dorofeevilya Россия  
Дата: 15.07.08 09:19
Оценка:
Здравствуйте, _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;
      }
   }
}
Re[5]: Ссылочные типы и get/set property
От: _FRED_ Черногория
Дата: 15.07.08 09:30
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>А если от MyRefClass наследовать специфичный класс для использования в качестве типа свойства MyProperty в MyTestClass:


Одно но:
D>class MyTestClass
D>{
D>   private MyNonNegativeRefClass _myRefClass;

D>   public MyRefClass MyProperty {
D>      get { return _myRefClass; }
D>      set {
D>         if(value == null) {
D>            throw new ArgumentNullException();
D>         }

D>         _myRefClass = value;
D>      }
D>   }
D>}


В выделенном месте необходимо приведение типов, то есть надо определить, на каком уровне известно про 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.
Re[6]: Ссылочные типы и get/set property
От: dorofeevilya Россия  
Дата: 15.07.08 09:35
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>В выделенном месте необходимо приведение типов, то есть надо определить, на каком уровне известно про MyNonNegativeRefClass.


Оппа-па! Я извиняюсь. Не заметил, когда правил сообщение. Конечно же, вполне устраивает:


class MyTestClass
{
   public MyNonNegativeRefClass MyProperty { ... }
}


Т. е. никаких приведений типов.
Re[7]: Ссылочные типы и get/set property
От: _FRED_ Черногория
Дата: 15.07.08 10:02
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

_FR>>В выделенном месте необходимо приведение типов, то есть надо определить, на каком уровне известно про MyNonNegativeRefClass.


D>Оппа-па! Я извиняюсь. Не заметил, когда правил сообщение. Конечно же, вполне устраивает:

D>Т. е. никаких приведений типов.

Тогда неплохо, я бы только посоветовал в реализации MyRefClass\MyNonNegativeRefClass использовать Non-virtual interface
Автор: minorlogic
Дата: 29.04.06
:

D>class MyRefClass
D>{
D>   private int _someNumber;

     protected virtual int SomeNumberCore // виртуальное, для наследников
     {
        get { return _someNumber; }
        set { _someNumber = value; }
     }

D>   public int SomeNumber // не виртуальное, для "внешнего мира"
D>   {
D>      get { return SomeNumberCore; }
D>      set { SomeNumberCore = value; }
D>   }
D>}

D>class MyNonNegativeRefClass : MyRefClass
D>{
D>   protected override int SomeNumberCore
D>   {
D>      // get { return base.SomeNumberCore; } - можно не перегружать
D>      set { if (value < 0) { throw new SomeException(); } else base.SomeNumberCore = value; }
D>   }
D>}
... << RSDN@Home 1 alpha 3 rev. 0>>
Help will always be given at Hogwarts to those who ask for it.
Re[8]: Ссылочные типы и get/set property
От: dorofeevilya Россия  
Дата: 15.07.08 11:03
Оценка:
Большое спасибо!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.