How do I enforce null checking?

2019-01-18 04:58发布

问题:

I'm working on a large project where, even with 10s of 1000s of automated tests and 100% code coverage, we're getting a ridiculous number of errors. About 95% of errors we get are NullReferenceExceptions.

Is there any way to enforce null-checking at compile time?

Barring that, is there any way to automagically enforce null-checking in unit tests without having to write the tests for null cases myself?

回答1:

You should look into Code Contracts. The static checker is only available for the higher-end VS editions, but that's basically what you're after.

There are plenty of resources online, and <plug> you can also read a prerelease version of the chapter on Code Contracts from the 2nd edition of C# in Depth - download chapter 15 for free. </plug> (The chapter is slightly out of date with respect to the latest and greatest build of Code Contracts, but nothing huge.)



回答2:

100% code coverage means nothing.

It is a false sense of security.

The only thing you're measuring is that you're executing all the lines of code.

Not:

  • That those lines of code are all the lines of code that should've been there
  • That those lines of code are operating correctly (are you testing all edge cases?)

For instance, if your procedure to deal with a fire contains 1 step "run out of the building", then even if that happens in 100% of the cases, perhaps a better procedure would be to "alert the fire department, try to stop the fire, then run out if all else fails".

There is nothing built into C# that will help you with this without you specifically going in and adding code, either code contracts (.NET 4.0) or specific IF-statements (<4.0).



回答3:

This isn't a technical solution, but a social one. Simply make it unacceptable in your environment to access a reference type without checking for null when the reference type has been modified in any way by outside code (another method call, etc). Unit Testing doesn't replace good old-fashioned code review.



回答4:

Is there any way to enforce null-checking at compile time?

Nope. The compiler cannot determine if the run-time reference variable is pointed to null.

And ruling out null producing statements (sets and returns) isn't enough either. Consider:

public class Customer
{
  public List<Order> Orders {get;set;}
}
  //now to use it
Customer c = new Customer;
Order o = c.Orders.First(); //oops, null ref exception;


回答5:

Defensive programming can only get you so far... maybe its just better to catch the exception and deal with it like any other.



回答6:

1) I think, the Resharper can suggest you to check some critical places in your code. For example, it suggests to add the [null reference check code] and adds it if you allow.

Try it. It will increase your experience if you need, of course.

2) Use "Fail Fast" pattern (or assert, assertions) in your code at the early stage of development application



回答7:

neither of those is possible with C# 3. you would have to use something like Spec#... i think C#4 may have some of that built into it, but i'm not sure about that.

spec#: http://research.microsoft.com/en-us/projects/specsharp



回答8:

You cannot have null checking at compile time as at compile time the objects are only Types and only at runtime the Types are converted to instances that have a concrete value ... here null.



回答9:

Maybe you should take a look at custom code analysis checkin policies for TFS

http://weblogs.asp.net/uruit/archive/2009/03/17/writing-custom-rules-for-tfs-2008-code-analysis-check-in-policy.aspx



回答10:

I may be wrong, but I think FxCop has a rule that suggests you add null reference checks to your code. You could try running your assemblies through the tool and see what it has to say.



回答11:

Check out Gendarme, it can be run post-build alongside your tests (possibly before them, if you wish) and has a few rules relating to null checks. You can also fairly trivially write your own.



回答12:

The .NET framework was looking to enforce compile time null reference checks by using an ! modifier.

public void MyMethod(!string cannotBeNull)

But alas, we don't have compile time checking. Your best bet is to minimize the amount occurrences for external callers to pass null values and then enforce null checks on public facing methods:

public class ExternalFacing
{
  public void MyMethod(string arg)
  {
     if (String.IsNullOrEmpty(arg))
        throw new ArgumentNullException(arg);

     implementationDependency.DoSomething(arg);
   }
}

internal class InternalClass
{
    public void DoSomething(string arg)
    {
         // shouldn't have to enforce null here.
    }
}

Then apply the appropriate unit tests to the External class to expect ArgumentNullExceptions.