English is not my first language, so I am not able to talk about semantic meaning of English names. I will not fight for "Close". I just want other method than "Dispose". Dispose always mean to me "Free all your resources
in a humble way and prepare to be garbage collected". The reasons I want other method is to separate resource cleaning from scoped operations. Both use cases differ - e.g. disposing resources should not throw, while scoped operation is free to throw if
necessary. Disposed object is probably going to be abandoned, while scoped operation can be freely reused as many times as needed, etc.
The rule against throwing from
stems from the fact that if
is called while unwinding the stack from an exception, having
throw an exception would cause the earlier exception to be lost. Eliminating that problem would eliminate the need for the rule. Instead, the rule would be "throw an exception if the cleanup was unable to leave things in the state the caller
expects". In many situations, such as with buffered files, a call to
may need to physically write data which the caller is expecting to be on the disk.
should not allow control to return normally to the caller unless data actually gets written. If the
occurs while code is unwinding from another exception, the caller really should be informed of both problems.
Neither resource-bearing nor scope-delineating objects are generally reused after disposal. Even if a scope-controlling object can be reused, the normal pattern is to ask that object for a lightweight scope-wrapping object at the start of each
block, and then dispose and abandon the wrapper object at the end. The unfortunate way C# treats structures in
makes the creation and abandonment of scope blocks slightly more expensive than it should be, but one-time-use wrappers are still the preferred idiom.
IDisposable docs refer only to concept of disposing resources. When people teach about this interface, they very often limit it to the concept of disposing resources. All this makes implementing IDisposable to get semantics of scoped operation a
hack. It can trick casual programmer. He can have good intentions to "fix" the perfectly good code so that it fits everything he learned about IDisposable. As a result, subtle bugs cripple in.
Where have you see "resources" defined? I would say that an object George acquires a resource if it asks something somewhere to put itself into a state which is beneficial to George but may be detrimental to other entities. For example, a
object may ask the file manager to associate a handle with a file and disallow access to that file by anyone who doesn't have that handle. Most kinds of scope-guard objects ask the controller of a scope to grant permission to do something;
disposing the received token says the permission is no longer required.
Even if the guard is lazy and unconditionally tells everyone they have permission, so the act of requesting permission and being told to proceed wouldn't prevent anyone else from doing likewise, the permission may still be viewed as an "untracked"
resource. At any given time, only one execution context at a time can be in a position to modify the object without causing corruption. The fact that a guard may tell a thread that it has permission to modify an object while another thread is doing so doesn't
mean the latter thread can safely modify the object without corruption. It merely makes it harder for the second thread to avoid erroneously modifying the object in such as way as to corrupt it.
Regarding the exceptions handling. While I am not big fan of throwing from Dispose(), this is only a guideline, not a strict rule. As I understand, connection is already aware of existing transactions, so that it can check if there are any pending.
Can't you just read the "abandoned from exception" state from transaction object and act accordingly?
Presently, the framework has no way of knowing whether a transaction object was abandoned because of an exception, or because the programmer forgot to commit. Normal design is to silently assume that any abandoned transaction should be rolled back, but when
there's no exception pending the rollback really shouldn't be silent.