Home:ALL Converter>C# - how to make a sequence of method calls atomic?

C# - how to make a sequence of method calls atomic?

Ask Time:2010-09-29T19:42:01         Author:Aadith Ramia

Json Formatter

I have to make a sequence of method calls in C# such that, if one of them fails, the subsequent methods should not be called. In short, the set of calls should be made atomic. How do I achieve this in C#?

Author:Aadith Ramia,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/3821253/c-sharp-how-to-make-a-sequence-of-method-calls-atomic
RichieHindle :

Preferably, get them to throw an exception when they fail and write your call sequence in a try/catch block.\n\nIf you can't do that for some reason, get them to return true on success and use &&:\n\nif (a() && b() && c())\n{\n ....\n\n\n(That's not \"atomic\" in the true sense of the word, but I don't think you're asking for true atomicity.)",
2010-09-29T11:44:19
Dave Cousineau :

\n if one of them fails, the subsequent methods should not be called. In short, the set of calls should be made atomic.\n\n\nThat is not what atomic means. As other answers have explained you can achieve this simply by checking the result of each method call and stopping when you get a certain result.\n\nAtomic means that either all of the methods are called or none of them are. So you guarantee that the entire block runs or doesn't run at all. This is not something you can achieve in C# code, or in most languages that I'm aware of. \n\nWhat you would have to do is separate checking results from final processing and queue up the final processing instead.\n\nSo instead of:\n\nbool Method1() {\n if (CheckCondition)\n return false;\n DoSomethingImportant();\n return true;\n}\n\nbool Method2() {\n if (CheckCondition)\n return false;\n DoSomethingElseImportant();\n return true;\n}\n\n...\n\nvar success1 = Method1();\nif (!success1)\n return;\n\nvar success2 = Method2();\nif (!success2)\n return; // oops we already did something important in method1\n\n\nDo something like:\n\nbool Method1() {\n if (CheckCondition)\n return false;\n queue.Enqueue(DoSomethingImportant);\n return true;\n}\n\nbool Method2() {\n if (CheckCondition)\n return false;\n queue.Enqueue(DoSomethingElseImportant);\n return true;\n}\n\n...\n\nvar success1 = Method1();\nif (!success1)\n return;\n\nvar success2 = Method2();\nif (!success2)\n return; // no problem, nothing important has been invoked yet\n\n// ok now we're completely successful, so now we can perform our important actions\n\nwhile (queue.Any()) {\n var doSomethingImportant = queue.Dequeue();\n doSomethingImportant();\n}\n\n\nThis still isn't anywhere's close to being actually \"atomic\", but it does give you a very basic \"all or nothing\" effect.",
2015-11-12T18:27:05
Richard J. Ross III :

If you are not catching exceptions, then if you throw an exception, all other methods called abort until a try block is found. So simply throw an exception where you need to have the atomic calls end (e.g. when it fails) and then catch it when you need to return to normal rutine.",
2010-09-29T11:44:21
Bear Monkey :

Here is a rough example of emulating a move operation with compensation if things go wrong. With exceptions thrown from your device copy methods on failure\n\nstring source = @\"C:\\file.txt\", dest = @\"D:\\file.txt\";\n\nbool fileCopied = false;\ntry\n{\n DeviceCopy(source, dest);\n fileCopied = true;\n DeviceDelete(source);\n}\ncatch\n{\n if (fileCopied)\n {\n DeviceDelete(dest);\n }\n throw;\n}\n\n\nOr with error codes e.g. could be bool for failed or check an integer\n\nif (DeviceCopy(source, dest))\n{\n if (!DeviceDelete(source))\n {\n if (!DeviceDelete(dest))\n {\n throw new IOException(\"Oh noes\");\n }\n }\n}\n",
2010-09-29T12:31:55
Isak Savo :

I think you're confusing the word \"atomic\" with something else. Atomic is when an operation cannot be interrupted and is usually done in multi threaded scenarios to protect shared resources.\n\nWhat you want is normal control flow logic and the solution depends on what your methods looks like.\n\nOne solution could be to have them return a boolean indicating whether or not it succeeded:\n\nbool success = false;\n\nsuccess = MethodA();\nif (!success)\n return;\nsuccess = MethodB();\nif (!success)\n return;\n\n// or even like this as suggested in another answer\nif (MethodA() &&\n MethodB() &&\n MethodC())\n{\n Console.WriteLine(\"All succeeded\");\n}\n\n\nYou could also use exceptions and wrap all your method calls inside a try-catch block. If one of them fails (throws an exception), your catch block will execute and nothing after that method call in the try-block will get a chance to run.\n\ntry\n{\n MethodA();\n MethodB();\n MethodC();\n}\ncatch (MyMethodFailedException)\n{\n // do something clever\n}\n\n\nIf you need rollback functionality, you have to get into transactions but that's a whole bigger topic.",
2010-09-29T11:51:52
Arthis :

TransactionScope might be what you need see here\n\nvoid RootMethod()\n{\n using(TransactionScope scope = new TransactionScope())\n {\n /* Perform transactional work here */\n SomeMethod();\n SomeMethod2();\n SomeMethod3();\n scope.Complete();\n }\n}\n",
2010-09-29T11:46:20
yy