5

I wonder if there is a simple manner to handle some kind of transaction in C#. Let us say that we have two properties and we would like to update their values. We could write:

A = GetA();
B = GetB();

The problem is, that if the exception will be thrown while assigning B, then object will be in inconsistant state, because A has been updated. We can solve this by storing the current value of A and catching an exception when dealing with B:

var tempA = A;
A = GetA(); // A is up to date
try { B = GetB(); } catch { A = tempA; } // B is up to date also or A is reverted

Even above solution is not save because the exception can be thrown while reverting A, but the point is, if there are built in mechanisms in .NET that simplyfies such operations?

I could imagine a statement like the below:

transaction { A = GetA(); B = GetB(); }

Or code construction like:

Transaction.Enter();
A = GetA();
B = GetB();
Transaction.Leave();

Before transaction the machine state will be stored and after transaction it will be reverted in case of exception. Is there something like that in .NET?

Ryszard Dżegan
  • 24,366
  • 6
  • 38
  • 56
  • [Software Transactional Memory](http://en.wikipedia.org/wiki/Software_transactional_memory)? – Damien_The_Unbeliever Jul 29 '13 at 12:59
  • `tempA = GetA(); B = GetB(); A = tempA`? – cHao Jul 29 '13 at 13:05
  • @cHao A = tempA maight throw an exception since we don't know how A setter is implemented. – Ryszard Dżegan Jul 29 '13 at 13:06
  • We don't *care* how A's setter is implemented. It's documented to throw exceptions in certain cases...or not. Exceptions aren't some magical thing that appear out of nowhere (thread aborts aside). They're errors, and in the case of a setter's failure, mean something went wrong that we were able to check beforehand. – cHao Jul 29 '13 at 13:09
  • @cHao Even if we know, that they can throw an exception, we can't sometimes predestinate when it can happen. It could depend on network conection or time. So we attempt to assign a property and we can't be sure that we succeed. – Ryszard Dżegan Jul 29 '13 at 13:15
  • If a setter is doing network access, or sleeping, or *anything* but setting its internal state appropriately, it's already horribly broken. *Setters don't act. They set.* They should not depend on non-deterministic factors. If you want action, use a method. – cHao Jul 29 '13 at 13:26
  • @cHao How about ObjectDisposedException while accessing a setter of different instance? Object could be disposed by another user or thread and a part of code that is attempting to update it may be unaware yet. – Ryszard Dżegan Jul 29 '13 at 13:37
  • @cHao Regardless of how we implement A assignment. We need to consider not A and B, but also C, D, E etc. There may be many of properties to assign. The question is about how to easy wrap that assignments into transaction. Is there such mechanism in .NET, how it works. – Ryszard Dżegan Jul 29 '13 at 13:40
  • There's no such built-in mechanism. TransactionScopes are well and good, but rely on everyone behaving in certain ways. If you can't trust the other code to do that, then the only viable solution is to take a snapshot of the entire state of the program and restore it on failure. – cHao Jul 29 '13 at 13:43

3 Answers3

10

"TransactionScope is not only for the databases. Every component that implements IEnlistmentNotification interface can participate in two-phase commit of the transaction scope.

Here is an example of transactional in-memory storage: http://www.codeproject.com/KB/dotnet/Transactional_Repository.aspx "

Source: https://stackoverflow.com/a/2273902/1714342

I think you can implement this IEnlistmentNotification interface and use TransactionScope

Community
  • 1
  • 1
Kamil Budziewski
  • 22,699
  • 14
  • 85
  • 105
4

You can use TransactionScope class.

Example:

using(var scope = new TransactionScope())
{
    DoAction1();
    DoAction2();

    scope.Complete();
}
Tamim Al Manaseer
  • 3,554
  • 3
  • 24
  • 33
  • Do you need `scope.complete()`? Seems counter intuitive to the concept of a `using` statement. – basher Jul 29 '13 at 13:26
  • you need to mark the transaction as complete before it gets disposed at the end of the "using" for it to be committed, if you don't mark it as complete, it will be rolledback at the end of the "using" scope. – Tamim Al Manaseer Jul 29 '13 at 13:36
2

There's no inbuilt feature for object transactions. But there are some third party libraries that provides this to support object state management.

you can take a look at this similar question.

https://stackoverflow.com/a/1765642/881798

Community
  • 1
  • 1
vendettamit
  • 14,315
  • 2
  • 32
  • 54