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 для всех ваших классов.