You code can be scoped within a scope or no scope at all. If there is not scope wrapping your code directly, your code will follow its caller's transaction scope. If there is no scope from above, then there is no transaction control in the .net domain.
If there is scope directly scope your code, your code behaves based on the TransactionScopeOption.
If it is TransactionScope.Required, then join the scope above, it is not null, or create scope if it is null.
If it is TransactionScope.RequiresNew, then always create a new Scope.
If its TransactionScope.Suppress, your code will not be part of transaction scope above. This means that if your code execute succesfully, even an error occurred afterward, and the error can rollback ambient transaction, but will not roll back your code. This is different from "no scope" case, in that case your code can be roll back if there is ambient transaction.
When to use what? First you don't care about your caller, your never know who is going to call your code.
If your code require transaction within(for example you have multiple insert/update/delete inside your code), and your code could be part of outer ambient transaction scope, use TransactionScope.Required. If your code require transaction within, but the transaction is independent from existing ambient transaction(outer transaction), becuase your does not want to be affected by the ambient transaction, you should use TransactionScope.ReqiresNew These two options are similar.
The difficult thing is when to use suppress and when to not use scope at all.
If your code do not want to affect by the ambient transaction, and there is only single insert/update/delete, you should use Transaction.Suppress. If there is only single insert/update/delete, and you want to be part of ambient transaction, do not use scope. Below is chart to help you how to use TransacationScope.