Tags: , , | Categories: .NET Posted by oleksii on 1/3/2011 5:50 PM | Comments (0)

Spec# has been for awhile in the developer world. Many people blogged about applying pre- (post-) conditions and invariants. To me it was interesting to see what is happening to the code that uses contracts.

This is what I checked. Presented below is a HashHelper class that contains a method with code contracts. It is used to get a hash code of a string.

internal sealed class HashHelper
{
	internal static string GetHash(string input, string hashAlgorithm)
	{
		Contract.Requires<ArgumentNullException>(
!
String.IsNullOrEmpty(input)); Contract.Requires<ArgumentNullException>(
!
String.IsNullOrEmpty(hashAlgorithm)); var alg = HashAlgorithm.Create(hashAlgorithm); var encoding = new UTF8Encoding(); byte[] bytesInput = encoding.GetBytes(input); byte[] hash = alg.ComputeHash(bytesInput); return Convert.ToBase64String(hash); } }

Basic usage sample

internal sealed class Program
{
	internal static void Main(string[] args)
	{
		string password = "123";
		string hashAlg = "sha256";
		string hash = HashHelper.GetHash(password, hashAlg);
	}
}

After building the project I checked the output code. The Contract type from HashHelper.GetHash is substituted by a generated runtime sibling __ContractsRuntime

public class HashHelper
{
    // Methods
    public static string GetHash(string input, string hashAlgorithm)
    {
        __ContractsRuntime.Requires<ArgumentNullException>(
!
string.IsNullOrEmpty(input), "input",
"!String.IsNullOrEmpty(
input)"); __ContractsRuntime.Requires<ArgumentNullException>(
!
string.IsNullOrEmpty(hashAlgorithm), "hashAlgorithm",
"!String.IsNullOrEmpty(hashAlgorithm)"
); HashAlgorithm alg = HashAlgorithm.Create(hashAlgorithm); byte[] bytesInput = new UTF8Encoding().GetBytes(input); return Convert.ToBase64String(alg.ComputeHash(bytesInput)); } }

The number of the generated methods and the methods' body of the __ContractsRuntime will depend on the code contracts usage in the user code as well as on the selected configuration (in the project's properties). A sample generated code is presented below. If condition is not violated it has the same performance impact as the usual if-throw construct.

[CompilerGenerated]
internal static class __ContractsRuntime
{
    // Methods
    [DebuggerNonUserCode, 
ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal static void Requires<TException>(bool condition, string message,
string
conditionText)
where
TException: Exception { if (!condition) { string str = ContractHelper.RaiseContractFailedEvent(
ContractFailureKind
.Precondition, message, conditionText, null); if (str != null) { Debug.Assert(false, str); } Exception exception = null; ConstructorInfo constructor = typeof(TException).GetConstructor(new Type[]
{ typeof(string), typeof(string) }); if (constructor != null) { if (constructor.GetParameters()[0].Name == "paramName") { exception = constructor.Invoke(
new object[] { message, str }) as Exception; } else { exception = constructor.Invoke(
new
object[] { str, message }) as Exception; } } else { constructor = typeof(TException).GetConstructor(
new
Type[] { typeof(string) }); if (constructor != null) { exception = constructor.Invoke(new object[] { str }) as Exception; } } if (exception == null) { throw new ArgumentException(str, message); } throw exception; } } }

Summary

Code contracts are injected into the output code. The size and content of the injected contracts depends on the usage and predefined configuration. Performance of the preconditions is the same as the standard if-throw constructs.

A whole project is available for download. It targets .NET 4 and MS VS 2010.

SmapleContracts.zip (3.99 kb) [Downloads: 66]

If you enjoyed this post, make sure you subscribe to my RSS feed!

blog comments powered by Disqus