В C или C++ я использовал бы препроцессор вместо если операторы для условного входа.
Microsoft работает над этим. Прочтите о программной транзакционной памяти.
Они используют несколько разных синтаксисов:
// For those who like arrows
Atomic.Do(() => {
obj.Prop1 = value;
obj.Prop2 = value;
obj.Recalculate();
});
// For others who prefer exceptions
try {
obj.Prop1 = value;
obj.Prop2 = value;
obj.Recalculate();
}
catch (AtomicMarker) {
}
// we may get this in C#:
atomic {
obj.Prop1 = value;
obj.Prop2 = value;
obj.Recalculate();
}
Об этом писал Жувал Лоуи. Вот ссылка на его исходную статью MSDN (я впервые услышал об этой идее в его превосходной книге о WCF). Вот пример кода из MSDN, который выглядит примерно так, как вы хотите:
public class MyClass
{
Transactional<int> m_Number = new Transactional<int>(3);
public void MyMethod()
{
Transactional<string> city = new Transactional<string>("New York");
using(TransactionScope scope = new TransactionScope())
{
city.Value = "London";
m_Number.Value = 4;
m_Number.Value++;
Debug.Assert(m_Number.Value == 5);
//No call to scope.Complete(), transaction will abort
}
}
Вы можете сделать копию объекта до выполнения методов и установки свойств. Затем, если результат вам не понравится, вы можете просто «откатиться» к копии. При условии, конечно, что у вас нет побочных эффектов, с которыми нужно бороться.
Нет, в настоящее время нет ничего подобного, встроенного в .net или C #.
Однако, в зависимости от ваших требований к использованию, вы могли бы реализовать что-то, что сделало бы эту работу за вас.
Ваш класс ObjectTransaction
будет сериализовать (или просто дублировать) объект и хранить копию во время транзакции. Если вы вызвали commit
, копию можно было бы просто удалить, но если вы вызвали откат, вы могли бы восстановить все свойства исходного объекта из копии.
Это предложение содержит множество предостережений.
Все сказанное, проект, над которым я работал несколько лет назад, действительно делал нечто подобное. При очень строгих ограничениях он может работать очень хорошо. Мы поддерживали только объекты данных внутреннего бизнес-уровня. И все они должны были унаследовать от базового интерфейса, который предоставлял некоторые дополнительные метаданные о типах свойств, и были правила о том, какие события могут запускаться установщиками свойств. Мы начинаем транзакцию, а затем привязываем объект к графическому интерфейсу. Если пользователь нажал кнопку ОК, транзакция была просто закрыта,
Нет, этот тип поддержки сегодня не существует для обычных управляемых объектов.
И здесь снова простое решение - в первую очередь не позволять вашим объектам переходить в недопустимое состояние. Тогда вам не нужно ничего откатывать, вам не нужно вызывать «Validate» и т. Д. Если вы удалите свои сеттеры и начнете думать об отправке сообщений объектам, чтобы что-то сделать с внутренними данными, а не устанавливать свойства, вы раскроет тонкости о вашем домене, которые иначе вы бы не узнали.
Как бы то ни было, полноценный STM - это небольшой выход, и я настоятельно рекомендую не использовать собственный.
К счастью, вы можете получить желаемую функциональность, осторожно проектирование ваших классов. В частности, неизменяемые классы "из коробки" поддерживают транзакционное поведение. Поскольку неизменяемые объекты возвращают новую копию себя каждый раз, когда свойство устанавливается, у вас всегда есть полная история изменений, которые можно откатить в случае необходимости.