views:

229

answers:

2

I have just got started using Microsoft's Code Contracts and already ran into a problem that I can't solve. Let's take this interface for which I'd like to specify a contract:

public interface IRandomWriteAccessible<T>
{
    T this[uint index] { set; }

    uint Length { get; }
}

The documentation says to use the ContractClass attribute when specifying a contract for an interface. However, the compiler will complain about this:

[ContractClass(typeof(IRandomWriteAccessibleContract<T>))]
//             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     <-- compiler error
public interface IRandomWriteAccessible<T>
{
    ...
}

[ContractClassFor(typeof(IRandomWriteAccessible<T>))]
//                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^          <-- compiler error
public sealed class IRandomWriteAccessibleContract<T> : IRandomWriteAccessible<T>
{
    ...
}

It seems that type parameters cannot be used for attributes.

How do I write a contract for my interface, or is this not possible with Code Contracts?

+1  A: 

Good question, but you can see the technical reasons behind this limitation, right?

The reason that you can't specify the ContractClass is because Blah<T> is not a class.

If you can make an interface for a concrete class by specifying a value for T, even though I'm sure this is sub-optimal.

John Gietzen
Well, yes, I suppose this makes sense (from the compiler's point of view). I still hope there's some kind of generic solution, because I don't feel like specifying the same contract for all possible types `T`...
stakx
Did @Steve Guidi's suggestion work?
John Gietzen
@ John: Yes, it worked!
stakx
+6  A: 

As mentioned by other comments in this question, you should remove the generic type identifier from your attribute usage as it can not be resolved at compile time:

[ContractClass(typeof(IRandomWriteAccessibleContract<>))] 
Steve Guidi
Woah, Nice. Did not know that that was an option...
John Gietzen
I looked this up in the C# language specification out of curiosity: The relevant chapters are _14.5.11 (typeof operator)_ and _25.5 (generics: constructed types)_, if anyone else is interested.
stakx
This is brilliant! I was also facing this issue for quite some time. If I face problem with this, I'm coming back with questions :D
Nayan
Also, if the generic class you're typeof()'ing takes more than one parameter, you have to use commas; for instance, typeof(YourType<,>), where YourType takes two type parameters.
Zor