Why are we not to throw these exceptions?

后端 未结 5 1700
名媛妹妹
名媛妹妹 2020-12-22 20:44

I came across this MSDN page that states:

Do not throw Exception, SystemException, NullReferenceException, or IndexOutOfRangeException intentionally f

相关标签:
5条回答
  • 2020-12-22 21:12

    Exception is the base type for all exceptions, and as such terribly unspecific. You shouldn’t ever throw this exception because it simply does not contain any useful information. Calling code catching for exceptions couldn’t disambiguate the intentionally thrown exception (from your logic) from other system exceptions that are entirely undesired and point out real faults.

    The same reason also applies to SystemException. If you look at the list of derived types, you can see a huge number of other exceptions with very different semantics.

    NullReferenceException and IndexOutOfRangeException are of a different kind. Now these are very specific exceptions, so throwing them could be fine. However, you still won’t want to throw these, as they usually mean that there are some actual mistakes in your logic. For example the null reference exception means that you are trying to access a member of an object which is null. If that’s a possibility in your code, then you should always explicitly check for null and throw a more useful exception instead (for example ArgumentNullException). Similarly, IndexOutOfRangeExceptions occur when you access an invalid index (on arrays—not lists). You should always make sure that you don’t do that in the first place and check the boundaries of e.g. an array first.

    There are a few other exceptions like those two, for example InvalidCastException or DivideByZeroException, which are thrown for specific faults in your code and usually mean that you are doing something wrong or you are not checking for some invalid values first. By throwing them knowingly from your code, you are just making it harder for the calling code to determine whether they were thrown due some fault in the code, or just because you decided to reuse them for something in your implementation.

    Of course, there are some exceptions (hah) to these rules. If you are building something that may cause an exception which exactly matches an existing one, then feel free to use that, especially if you are trying to match some built-in behavior. Just make sure you choose a very specific exception type then.

    In general though, unless you find a (specific) exception that fills your need, you should always consider creating your own exception types for specific expected exceptions. Especially when you are writing library code, this can be very useful to separate the exception sources.

    0 讨论(0)
  • 2020-12-22 21:19

    As you point out, in the article Creating and Throwing Exceptions (C# Programmming Guide) under the topic Things to Avoid When Throwing Exceptions, Microsoft does indeed list System.IndexOutOfRangeException as an exception type that should not be thrown intentionally from your own source code.

    In contrast, however, in the article throw (C# Reference), Microsoft seems to violate its own guidelines. Here is a method that Microsoft included in its example:

    static int GetNumber(int index)
    {
        int[] nums = { 300, 600, 900 };
        if (index > nums.Length)
        {
            throw new IndexOutOfRangeException();
        }
        return nums[index];
    }
    

    So, Microsoft itself isn't being consistent as it demonstrates the throwing of IndexOutOfRangeException in its documentation for throw!

    This leads me to believe that at least for the case of IndexOutOfRangeException, there may be occasions where that exception type can be thrown by the programmer and be considered an acceptable practice.

    0 讨论(0)
  • 2020-12-22 21:26

    When I read your question, I asked myself under what conditions one would want to throw the exception types NullReferenceException, InvalidCastException or ArgumentOutOfRangeException.

    In my opinion, when encountering one of those exception types, I (the developer) feel concerned by the warning in the sense that the compiler is talking to me. So, allowing you (the developer) to throw such exception types is equivalent to (the compiler) selling the responsibility. For instance, this suggests the compiler should now allow the developer to decide whether an object is null. But making such a determination should really be the job of the compiler.

    PS: Since 2003 I have been developing my own exceptions so I can throw them as I wish. I think it is considered a best practice to do so.

    0 讨论(0)
  • 2020-12-22 21:33

    I suspect the intent with the last 2 is to prevent confusion with inbuilt exceptions that have an expected meaning. However, I'm of the opinion that if you are preserving the exact intent of the exception: it is the correct one to throw. For example, if you are writing a custom collection, it seems entirely reasonable to use IndexOutOfRangeException - clearer and more specific, IMO, than ArgumentOutOfRangeException. And while List<T> might choose the latter, there are at least 41 places (courtesy of reflector) in the BCL (not including arrays) that throw bespoke IndexOutOfRangeException - none of which are "low level" enough to deserve special exemption. So yeah, I think you can justly argue that that guideline is silly. Likewise, NullReferenceException is kinda useful in extension methods - if you want to preserve the semantic that:

    obj.SomeMethod(); // this is actually an extension method
    

    throws a NullReferenceException when obj is null.

    0 讨论(0)
  • 2020-12-22 21:33

    Putting the discussion about NullReferenceException and IndexOutOfBoundsException aside:

    What about catching and throwing System.Exception. I've thrown this type of exception in my code a lot and I was never screwed by it. Similarly, very often I catch the unspecific Exception type, and it also worked pretty well for me. So, why is that?

    Usually users argue, that they should be able to distinguish error causes. From my experience, there are just a very few situations where you would want to handle different exception types differently. For those cases, where you expect users to handle errors programmatically, you should throw a more specific exception type. For other cases, I'm not convinced by the general best practice guideline.

    So, regarding throwing Exception I don't see a reason to prohibit this in all cases.

    EDIT: also from the MSDN page:

    Exceptions should not be used to change the flow of a program as part of ordinary execution. Exceptions should only be used to report and handle error conditions.

    Overdoing catch clauses with individual logic for different exception types are not best practice, either.

    0 讨论(0)
提交回复
热议问题