开发者

C# Code Contracts: How to validate parameters of interfacemethod defined in other assembly?

I have a situation I don't know how it's supposed to be solved. According to the user manual section 3, a contractmethod, i.e. Require or Ensure, is not allowed in overriding methods/properties or interface implementations. The contract methods should be declared in the root virtual/abstract method and since you can't declare code in an abstract method, you have to work with the ContractClassAttribute and ContractClassForAttribute. The same goes for contractmethods for interfacemembers(and their implementations).

But what if I want to use an interface I haven't created myself? For example IL开发者_运维百科ist<T> doesn't implement these contract methods, but I can't set the ContractClassAttribute on it either. How should I do parametervalidation in for example the implementation of IList<T>.this[int]? The following solutions aren't allowed:

T IList<T>.this[int i]
{
    get
    {
        Contract.Requires(i >= 0);//not allowed

        if (i < 0)
            throw new ArgumentException();
        Contract.EndContractBlock();//also not allowed
        ...
    }
}

Are the legacy if-then-throw statements without EndContractBlock the only solution?


First of all, IList<T> already specifies that precondition. I just tried it to be sure: "Precondition failed: index >= 0".

Furthermore, as I understand it, post conditions are allowed, only preconditions aren't.

If, you would still like to add other preconditions, I believe this answers your question: http://social.msdn.microsoft.com/Forums/en/codecontracts/thread/af403bbc-ca4e-4546-8b7a-3fb3dba4bb4a

It basicly comes down to the fact that you are not meant to do so, as that would defy the purpose of code contracts.


The reason you can't add preconditions is the same reason you can't do this:

interface IInterface
{
    void Foo(Parent x);
}

class Implementation : IInterface
{
    void Foo(Child x);
}

It's related to (co-/contra-)variance — method parameters are contravariant, meaning the type you accept has to be "at least as big/liberal" as the type that the interface specifies.

Adding more pre-conditions is making the type smaller/stricter, in the same way that accepting a subclass of the type would be (like in the example above).* You can't do this for obvious reasons — a class which implements the interface might not work when passed the correct arguments! If you flipped Parent & Child it would be ok.

With method return types it's the other way around: they're covariant, meaning you have to be "at least as small/strict" as the type the interface specifies. This is why you can add post-conditions, because you're making the type "smaller/stricter". It's the same reason why this works:

interface IInterface
{
    Parent Foo();
}

class Implementation : IInterface
{
    Child Foo();
}

* (This actually raises the question of whether you should be able to remove pre-conditions from implementing classes. This would be an interesting feature.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜