Parameter Validation Best Practices

北战南征 提交于 2019-12-05 15:52:20

问题


Imagine you have an application which is some kind of front-end to all your business logic. This front-end has a lot of DLLs upon which it depends, and the methods in those DLLs may call each other repeatedly upon a single execution of a given method in the front-end. If the users of your application do not directly access those DLLs, should you...

1) Risk a (small) performance hit and validate parameters in each of those methods, even if you can end up validating the same parameters some 5 times; or

2) Risk unexpected behaviour and assume that, as you validate input parameters, all the other possible parameters passed to and from your internal code are valid (for example, neither null nor empty)?

Edit: Just to give an example, suppose you have a Regex RegexA and a method

internal bool Matches(string expression)
{
    return RegexA.IsMatch(expression);
}

IsMatch will throw an exception on a null parameter, but not on the empty string. If you know beforehand that an empty string will never be a match to that Regex, should you use if (String.IsNullOrEmpty(expression)) before, even knowing that it may be validated for nullity inside the IsMatch framework method? In this case you are clearly repeating a validation, but is it better to repeat it or to risk?


回答1:


Usually parameter checks are very cheap, even if called thousands of times. For example test if a value is null, a string or Collection is emtpy a number is in a given range.

But beware that checks may be expensive, so think twice: Evaluating a regex on a large string, checking if a file exists, checking that all elements in a collection meets a certain criteria.

I would also only recommend checking only in public or protected methods. Note that all public methods with unchecked parameters are potential risks!

EDIT/another thought: If a method does not use the parameters but is just passing it to another method then you may also omit the checking. Only the method which is actually using these parameters for itself should do the checking.

This is because if the requirements of the parameters change you need to change the validations in multiple places, risking inconsistency.




回答2:


Unless the validation of the parameter is going to be expensive, I would go with #1. Fail-fast behavior lets you catch bugs in a fraction of the time, which will save you a lot more time than it takes to write a few guard statements at the beginning of each method.

One technology you may be interested to help with this is .NET's Code Contracts, which allow you to create quasi-compile-time checks to ensure that nobody calls a method without ensuring that the inputs match the expected patterns.

I personally tried using Code Contracts, and found that there was a little too much overhead for my needs. However, I appreciated the syntax, so I made a class to help with these guard statements, but which only works at run-time. It works like this:

public void ChangeUserName(int userId, string name)
{
    Require.ThatArgument(userId > 0);
    Require.ThatArgument(!string.IsNullOrWhitespace(name,
        () => "Usernames must be non-empty strings");
    var user = GetUser(userId);
    Require.That(user != null, 
        () => new UserDoesNotExistException("No user exists with ID " + userId));
    user.Name = name;
    ...
}

And one final technology that helps a lot for these checks is Resharper's Annotations. For example, consider the following method:

[CanBeNull]
public User GetUser(int userId)
{
    var user =  ... // Get the user from the db
    return user;
}

By telling Resharper that the method might return a null value, it will know to warn you if you haven't done a null check on user before trying to access user.Name. Another annotation is available to tell Resharper that Require.That(user != null) constitutes a null check. You could also re-write your method like this:

[NotNull]
public User GetUser(int userId)
{
    Require.ThatArgument(userId > 0);
    var user =  ... // Get the user from the db
    Require.That(user != null)
    return user;
}

By marking this method as NotNull, Resharper can automatically tell you that user != null will always resolve to true so you don't have to check for it. There are all kinds of fun stuff you can do to make validation easier.




回答3:


As an author of a library, you cannot assume that the consumers have done proper validation of inputs, so you as a library author would want to ensure the arguments are valid before going to work with them.

As a consumer of a library, if you know what inputs are going to cause the library to fail, why would you pass those inputs to that library? Validate against them so that you can perhaps prompt your user for better inputs or otherwise cancel whatever process you are in.

The fact that you might be the author of both the library and the consumer is not particularly relevant, in my opinion, as this relationship may very well change.




回答4:


Very interesting topic :)

in general you should implement a "validation facade" lower than the user interface and at the lowest possible level commonly accessed by user interface and external services.

you can check for null and validate input also in the UI just to avoid a useless round-trip to the server, client side validation is a good practice, still you cannot trust the caller to only pass you valid values.




回答5:


You may get mixed opinions, but in my view..it is best to do validation in both the layers. In the front and the business logic (dlls as you call it)



来源:https://stackoverflow.com/questions/6510171/parameter-validation-best-practices

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!