C# на отслеживание изменений вложенных свойств

У меня есть универсальный класс с одним аргументом, который представляет элемент сторонней библиотеки DLL с целью сериализации объектов типа T. То, что я хотел бы сделать, это добавить "грязную" карту в мой класс и лениво запускать ее всякий раз, когда изменяется одно из вложенных свойств моего элемента.

Можно ли при обращении к свойству поймать запрос и определить, какое свойство изменяется? Что, если выполняется SET, я могу записать, что подсвойство P теперь грязное и должно быть сохранено? Или хотя бы один бит, который указывает, что что-то изменилось?

  public class ResourceSerializer<T>
  where T : Base, new()
  {
   T element;
   Dictionary<String,Boolean> dirtyMap;

   public T Element { get { return this.getElement(); } }
   public Boolean IsDirty { get; private set; }

   public ResourceSerializer()
   {
     dirtyMap = new Dictionary<string,bool>();
     element = new T();
     // code to reflect back upon T's Properties and build out the dirtyMap. 
     // I already can do this I just omitted it.
     // in my Person example there would be keys:  'FirstName', 'LastName', 'Age', 'Gender', 'PrimaryAddress'
    }


   // how can I call this programmatically?
   void flagDirty(String property)
   {
     dirtyMap[property] = true;
     this.IsDirty = true;
   }
   T getElement()
   {
     // In case I need to do a thing before returning the element. 
     // Not relevant to the question at hand.
     return this.element;
   }
 }

несколько продвинутый пример "базы". Вы можете видеть, как мне нужно повторять свои действия, поскольку не все примитивно. У меня есть класс уровня менеджера, который регистрирует все эти объекты ResourceSerializer.

 public class Base
 {
   public Base()
   {

   }
 }
 public enum gender
 {
   Male,
   Female,
   Other,
   Unspecified,
 }
  public class Address : Base
 {
   public String Street { get; set; }
   public String State { get; set; }
   public String Zip { get; set; }
   public Address() : base()
   {

   }
 }
 public class Person : Base
 {
   public String FirstName { get; set; }
   public String LastName { get; set; }
   public Int16 Age { get; set; }
   public gender Gender { get; set; }
   public Address PrimaryAddress { get; set; }
   public Person() : base()
   {

   }
 }
 public class Patient : Person
 {
   public Person PrimaryContact { get; set; }
   public Patient() : base()
   {

   }
 }

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

  public class DoThing
  {
    public DoThing()
    {
      ResourceSerializer<Person> person = new ResourceSerializer<Person>();
      person.Element.Age = 13; // catch this and mark 'Age' as dirty.
    }
  }

1 ответ

Решение

Без пользовательского сеттера нет, ничего не поделаешь.

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

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

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

Вначале много работы, но если у вас есть куча классов, кода будет гораздо меньше, чем для реализации INotifyPropertyChanged для всех ваших классов.

Другие вопросы по тегам