Can code contracts replace parameter validation?

Another guy asked a similar question but the answer isn't clear to me.

We have a lot of parameter validation code in our project. They are mostly null parameter checks in public methods only:

if (param == null)
{
  throw new ArgumentNullException("param");
}

Those checks aren't part of specification. Their main utility is to get saner stack dumps in case of a programming error. If such a simple check isn't done, you can end up ten levels deep in the stack in a random spot right in the middle of the some other library with a NullReferenceException . This makes the whole backtracing to the root cause process longer. Validation checks are semantically clear and allow you to catch the problems earlier.

Since we're doing that a lot, we have been looking for shorter ways of doing such checks. Such as:

ArgumentHelper.ThrowIfNull(param, "param");

or a similar syntax. We'd like to avoid the overhead basically. The if-throw syntax makes the code unnecessarily long.

When I was experimenting with such syntax I noticed that I was converging to a similar syntax like assertions and code contracts. Code contracts are very attractive because of the possibiltiy of static analysis and catching bugs early in the development cycle.

However as I understand code contracts weren't designed to remedy "input validation" problem or any kind of validation problem whatsoever. Because the exceptions raised by it are not meant to be caught. They are not there for making debugging easier either because default behavior is stripping the code from such checks in the release build. The rewriter just seems like a hack around it and it's not very performant either.

What I understand from all that is "static verification" and "parameter validation" have different goals so they cannot be interchanged. Yet using Code.Contracts for my prologue if-then-throw s sounded so natural at the beginning I wonder if I got something wrong.

My question is: Is using code contracts for parameter validation valid? Is there a clear question I can ask to any validation code and come up with an answer like: "yes you can use code contracts to check this" and "no you can't use code contracts to check that"? How do I make the distinction?

I came up with "would that function keep working correctly if I removed the contract statement?". Is that a correct approach?


Hmm. I'm the guy who wrote the answer that wasn't clear :-/. I'll have a stab at phrasing it a different way.

I'd say your approach is correct, but there's a complication. It might help to look at this from the perspective of user input validation. Take this code:

public void SetUserName(string userInput)
{
    if(String.IsNullOrWhitespace(userInput))
        throw new ValidationException("...");       
}

It's perfectly possible for the user to forget to input a new username; the empty string is one of the expected inputs that this method might receive, and it's designed to handle them.

Now lets say we add a method that processes the user input:

public string DoSomethingToUserName(string userInput)
{
    return userInput.ToLower();
}

This method assumes that userInput is not null; as you say, it won't work without that being true. If a null value is passed in, someone has made a programming error. So we can state that as part of the interface of the method, and get the static verifier to warn us if someone's goofed:

public string DoSomethingToUserName(string userInput)
{
    Contract.Requires(userInput != null);

    return userInput.ToLower();
}

If this happens at runtime, that means not only did someone make a programming error, but the static verifier could not detect the problem, either due to some Reflection use or similar, or just because there's a bug in it. So, it's always a good idea to turn on contract rewrites, at least on public surface contracts, just in case.

So, we use contracts to check parameters only where the method wouldn't work without them; they are preconditions for the successful operation of the method. If the precondition fails, then someone goofed, and we don't want to catch the exception because it's revealing a bug.

The complication comes when DoSomethingToUserName doesn't actually manipulate the user name itself:

public string DoSomethingToUserName(string userInput)
{
    return DoFirstThingToUserName(userInput);
}

private string DoFirstThingToUserName(string userInput)
{
    Contract.Requires(userInput != null);

    return userInput.ToLower();
}

Now, DoFirstThingToUserName will fail if the user name is null; DoSomethingToUserName doesn't care whether it is or not. However, no-one will be able to tell by looking at the public interface that userInput must be pre-validated. So we need to announce the contract to the outside world:

public string DoSomethingToUserName(string userInput)
{
    Contract.Requires(userInput != null);

    return DoFirstThingToUserName(userInput);
}

private string DoFirstThingToUserName(string userInput)
{
    Contract.Requires(userInput != null);

    return userInput.ToLower();
}

A quick answer is no, you can't replace input validation with code contracts. The main difference is that input validation shouldn't throw exceptions on invalid data coming in because it's not an exceptional situation. On the other hand, contract violation always signalize a bug in your system and thus should throw exceptions or even crush your app (following fail-fast principle).

Check my blog post: Code contracts vs input validation

链接地址: http://www.djcxy.com/p/23742.html

上一篇: 代码合同静态检查似乎没有工作

下一篇: 代码合同可以取代参数验证吗?