In writing some code to mimic an as-complete-as-possible emulation of System.Array, I have come across something that I find confusing and dangerous.
With the following method signature:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static int BinarySearch<T>(T[] array, T value, IComparer<T> comparer)
A method is declared with a contract saying that it will definitely not corrupt any state, even itself, if there is a failure. It also implies that some code external to the contract will be called via the comparer value, and IComparer<T>.Compare does not require a reliability contract; a call to comparer.Compare(x,y) can certainly corrupt state and violate the contract.
How is this valid? I'm not an expert on the uses of constrained execution... will a constrained execution environment inspect the Compare method at runtime, and cause an exception if the contract is expected to be enforced? Is this a hole in the reliability contract?
Or, are constrained execution regions CIL voodoo that I should avoid in non-framework code? I want to keep as close as possible behavior to native System.Array, and so I would like to maintain the same ReliabilityContract attributes where the underlying implementation supports it; but it seems to me that even the internals can't guarantee the contract, so I am quite puzzled how I could guarantee the contract.
AFAIK, CERs are a very advanced feature and are used very rarely. Unless you really want your class to be usable in a CER (or if you're not sure what CERs actually are), you shouldn't specify any
ReliabilityContract.If you still want to investigate CERs, read Stephen Toub's Keep Your Code Running with the Reliability Features of the .NET Framework. I think the most relevant part of that article is (emphasis mine):
I think the highlighted section means that
BinarySearchshouldn't have been marked asWillNotCorruptState. Or it's possible that the case with a delegate is more transparent than callingEquals()of a passed inobject, so the attribute is actually okay here.In any case, I think that to be on the safe side, you shouldn't specify any
ReliabilityContracts, unless you really know what you're doing and you really need it.