Depends on what you really mean by "contract" in this case. In any case:
- .NET/C# interfaces are a weak form of contracts. All they do is require a class to implement some methods, everything else is left to the documentation.
- There's nothing stopping an implementation to exceed contract requirements.
- Stream's IDisposable implementation exceeds contract requirements and documents that thus becoming a contract in itself because that's how contracts are defined in .NET/C#.
- Contract or not, the fact that Stream.Dispose writes changes to the store was documented and no matter how the internal implementation changs this must remain true.
And since _stevo mentioned transactions: the TransactionScope is a perfect example of exceeding IDisposable's "contract". It does the opposite of Stream, it rollbacks any changes that were made. Not only it does that but that's the only way to rollback a transaction
because there's no Rollback method provided. Even more, TransactionScope.Dispose documentation does not mention anything about realising managed and unmanaged resources.
I guess TransactionScope's creation was the moment when IDisposable silently converted to a general purpose interface beyond its "release managed and unmanaged resources" original intent. Because this interface was used by the using C# keyword it is now used
to model scope based lifetime similar to C++. Now this is not strictly related to "to Close or not to Close" but about what an "IDisposable contract" can really mean.