{"id":301,"date":"2023-10-20T13:21:01","date_gmt":"2023-10-20T05:21:01","guid":{"rendered":"https:\/\/miie.net\/?p=301"},"modified":"2023-10-20T13:21:01","modified_gmt":"2023-10-20T05:21:01","slug":"pro-c10-chapter-7-understanding-structured-exception-handling","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=301","title":{"rendered":"Pro C#10 CHAPTER 7 Understanding Structured Exception Handling"},"content":{"rendered":"<h1>CHAPTER 7 Understanding Structured Exception Handling<\/h1>\n<p>\u7b2c7\u7ae0  \u4e86\u89e3\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406<\/p>\n<p>In this chapter, you will learn how to handle runtime anomalies in your C# code through the use of structured exception handling. Not only will you examine the C# keywords that allow you to handle such matters (try, catch, throw, finally, when), but you will also come to understand the distinction between application-level and system-level exceptions, as well as the role of the System.Exception base class.<br \/>\n\u5728\u672c\u7ae0\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u901a\u8fc7\u4f7f\u7528\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u6765\u5904\u7406 C# \u4ee3\u7801\u4e2d\u7684\u8fd0\u884c\u65f6\u5f02\u5e38\u3002\u60a8\u4e0d\u4ec5\u5c06\u68c0\u67e5\u5141\u8bb8\u60a8\u5904\u7406\u6b64\u7c7b\u95ee\u9898\u7684 C# \u5173\u952e\u5b57\uff08\u5c1d\u8bd5\u3001\u6355\u83b7\u3001\u629b\u51fa\u3001\u6700\u540e\u3001\u4f55\u65f6\uff09\uff0c\u800c\u4e14\u8fd8\u5c06\u4e86\u89e3\u5e94\u7528\u7a0b\u5e8f\u7ea7\u548c\u7cfb\u7edf\u7ea7\u5f02\u5e38\u4e4b\u95f4\u7684\u533a\u522b\uff0c\u4ee5\u53ca System.Exception \u57fa\u7c7b\u7684\u4f5c\u7528\u3002<\/p>\n<p>This discussion will lead into the topic of building custom exceptions and, finally, to a quick look at some exception-centric debugging tools of Visual Studio.<br \/>\n\u6b64\u8ba8\u8bba\u5c06\u5f15\u51fa\u751f\u6210\u81ea\u5b9a\u4e49\u5f02\u5e38\u7684\u4e3b\u9898\uff0c\u6700\u540e\u5feb\u901f\u6d4f\u89c8 Visual Studio \u7684\u4e00\u4e9b\u4ee5\u5f02\u5e38\u4e3a\u4e2d\u5fc3\u7684\u8c03\u8bd5\u5de5\u5177\u3002<\/p>\n<h2>Ode to Errors, Bugs, and Exceptions<\/h2>\n<p>\u9519\u8bef\u3001\u9519\u8bef\u548c\u5f02\u5e38<\/p>\n<p>Despite what our (sometimes inflated) egos may tell us, no programmer is perfect. Writing software is a complex undertaking, and given this complexity, it is quite common for even the best software to ship with various problems. Sometimes the problem is caused by bad code (such as overflowing the bounds of an array). Other times, a problem is caused by bogus user input that has not been accounted for in the application\u2019s code base (e.g., a phone number input field assigned to the value Chucky). Now, regardless of the cause of the problem, the end result is that the application does not work as expected. To help frame the upcoming discussion of structured exception handling, allow me to provide definitions for three commonly used anomaly-centric terms.<br \/>\n\u5c3d\u7ba1\u6211\u4eec\u7684\uff08\u6709\u65f6\u662f\u81a8\u80c0\u7684\uff09\u81ea\u6211\u53ef\u80fd\u4f1a\u544a\u8bc9\u6211\u4eec\uff0c\u4f46\u6ca1\u6709\u4e00\u4e2a\u7a0b\u5e8f\u5458\u662f\u5b8c\u7f8e\u7684\u3002\u7f16\u5199\u8f6f\u4ef6\u662f\u4e00\u9879\u590d\u6742\u7684\u5de5\u4f5c\uff0c\u9274\u4e8e\u8fd9\u79cd\u590d\u6742\u6027\uff0c\u5373\u4f7f\u662f\u6700\u597d\u7684\u8f6f\u4ef6\u4e5f\u4f1a\u9047\u5230\u5404\u79cd\u95ee\u9898\u3002\u6709\u65f6\u95ee\u9898\u662f\u7531\u9519\u8bef\u4ee3\u7801\u5f15\u8d77\u7684\uff08\u4f8b\u5982\u6ea2\u51fa\u6570\u7ec4\u7684\u8fb9\u754c\uff09\u3002\u5176\u4ed6\u65f6\u5019\uff0c\u95ee\u9898\u662f\u7531\u672a\u5728\u5e94\u7528\u7a0b\u5e8f\u7684\u4ee3\u7801\u5e93\uff08\u4f8b\u5982\uff0c\u5206\u914d\u7ed9\u503c Chucky \u7684\u7535\u8bdd\u53f7\u7801\u8f93\u5165\u5b57\u6bb5\uff09\u3002\u73b0\u5728\uff0c\u65e0\u8bba\u95ee\u9898\u7684\u539f\u56e0\u662f\u4ec0\u4e48\uff0c\u6700\u7ec8\u7ed3\u679c\u90fd\u662f\u5e94\u7528\u7a0b\u5e8f\u65e0\u6cd5\u6309\u9884\u671f\u5de5\u4f5c\u3002\u4e3a\u4e86\u5e2e\u52a9\u6784\u5efa\u5373\u5c06\u8fdb\u884c\u7684\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u8ba8\u8bba\uff0c\u8bf7\u5141\u8bb8\u6211\u63d0\u4f9b\u4e09\u4e2a\u5e38\u7528\u7684\u4ee5\u5f02\u5e38\u4e3a\u4e2d\u5fc3\u7684\u672f\u8bed\u7684\u5b9a\u4e49\u3002<\/p>\n<p>\u2022Bugs: These are, simply put, errors made by the programmer. For example, suppose you are programming with unmanaged C++. If you fail to delete dynamically allocated memory, resulting in a memory leak, you have a bug.<br \/>\n\u9519\u8bef\uff1a\u7b80\u5355\u5730\u8bf4\uff0c\u8fd9\u4e9b\u662f\u7a0b\u5e8f\u5458\u72af\u7684\u9519\u8bef\u3002\u4f8b\u5982\uff0c\u5047\u8bbe\u60a8\u6b63\u5728\u4f7f\u7528\u975e\u6258\u7ba1C++\u8fdb\u884c\u7f16\u7a0b\u3002\u5982\u679c\u65e0\u6cd5\u5220\u9664\u52a8\u6001\u5206\u914d\u7684\u5185\u5b58\uff0c\u4ece\u800c\u5bfc\u81f4\u5185\u5b58\u6cc4\u6f0f\uff0c\u5219\u5b58\u5728\u9519\u8bef\u3002<br \/>\n\u2022User errors: User errors, on the other hand, are typically caused by the individual running your application, rather than by those who created it. For example, an end user who enters a malformed string into a text box could very well generate an error if you fail to handle this faulty input in your code base.<br \/>\n\u7528\u6237\u9519\u8bef\uff1a\u53e6\u4e00\u65b9\u9762\uff0c\u7528\u6237\u9519\u8bef\u901a\u5e38\u662f\u7531\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u7684\u4e2a\u4eba\u5f15\u8d77\u7684\uff0c\u800c\u4e0d\u662f\u7531\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\u7684\u4eba\u5f15\u8d77\u7684\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u672a\u80fd\u5728\u4ee3\u7801\u5e93\u4e2d\u5904\u7406\u6b64\u9519\u8bef\u8f93\u5165\uff0c\u5219\u5728\u6587\u672c\u6846\u4e2d\u8f93\u5165\u683c\u5f0f\u9519\u8bef\u7684\u5b57\u7b26\u4e32\u7684\u6700\u7ec8\u7528\u6237\u5f88\u53ef\u80fd\u4f1a\u751f\u6210\u9519\u8bef\u3002<br \/>\n\u2022Exceptions: Exceptions are typically regarded as runtime anomalies that are difficult, if not impossible, to account for while programming your application. Possible exceptions include attempting to connect to a database that no longer exists, opening a corrupted XML file, or trying to contact a machine that is currently offline. In each of these cases, the programmer (or end user) has little control over these \u201cexceptional\u201d circumstances.<br \/>\n\u5f02\u5e38\uff1a\u5f02\u5e38\u901a\u5e38\u88ab\u89c6\u4e3a\u8fd0\u884c\u65f6\u5f02\u5e38\uff0c\u5728\u5bf9\u5e94\u7528\u7a0b\u5e8f\u8fdb\u884c\u7f16\u7a0b\u65f6\u5f88\u96be\uff08\u5982\u679c\u4e0d\u662f\u4e0d\u53ef\u80fd\u7684\u8bdd\uff09\u8003\u8651\u8fd9\u4e9b\u5f02\u5e38\u3002\u53ef\u80fd\u7684\u5f02\u5e38\u5305\u62ec\u5c1d\u8bd5\u8fde\u63a5\u5230\u4e0d\u518d\u5b58\u5728\u7684\u6570\u636e\u5e93\u3001\u6253\u5f00\u635f\u574f\u7684 XML \u6587\u4ef6\u6216\u5c1d\u8bd5\u8054\u7cfb\u5f53\u524d\u5904\u4e8e\u8131\u673a\u72b6\u6001\u7684\u8ba1\u7b97\u673a\u3002\u5728\u6bcf\u79cd\u60c5\u51b5\u4e0b\uff0c\u7a0b\u5e8f\u5458\uff08\u6216\u6700\u7ec8\u7528\u6237\uff09\u51e0\u4e4e\u65e0\u6cd5\u63a7\u5236\u8fd9\u4e9b\u201c\u7279\u6b8a\u201d\u60c5\u51b5\u3002<\/p>\n<p>Given these definitions, it should be clear that .NET structured exception handling is a technique for dealing with runtime exceptions. However, even for the bugs and user errors that have escaped your view, the runtime will often generate a corresponding exception that identifies the problem at hand. By way of a few examples, the .NET base class libraries define numerous exceptions, such as FormatException, IndexOutOfRangeException, FileNotFoundException, ArgumentOutOfRangeException, and so forth.<br \/>\n\u9274\u4e8e\u8fd9\u4e9b\u5b9a\u4e49\uff0c\u5e94\u8be5\u6e05\u695a\u7684\u662f\uff0c.NET \u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u662f\u4e00\u79cd\u5904\u7406\u8fd0\u884c\u65f6\u5f02\u5e38\u7684\u6280\u672f\u3002\u4f46\u662f\uff0c\u5373\u4f7f\u5bf9\u4e8e\u5df2\u9003\u8131\u89c6\u56fe\u7684 bug \u548c\u7528\u6237\u9519\u8bef\uff0c\u8fd0\u884c\u65f6\u901a\u5e38\u4e5f\u4f1a\u751f\u6210\u76f8\u5e94\u7684\u5f02\u5e38\u6765\u6807\u8bc6\u624b\u5934\u7684\u95ee\u9898\u3002\u987a\u4fbf\u8bf4\u4e00\u4e0b\u5728\u51e0\u4e2a\u793a\u4f8b\u4e2d\uff0c.NET \u57fa\u7c7b\u5e93\u5b9a\u4e49\u4e86\u5927\u91cf\u5f02\u5e38\uff0c\u4f8b\u5982 FormatException\u3001IndexOutOfRangeException\u3001FileNotFoundException\u3001ArgumentOutOfRangeException \u7b49\u3002<\/p>\n<p>Within the .NET nomenclature, an exception accounts for bugs, bogus user input, and runtime errors, even though programmers may view each of these as a distinct issue. However, before I get too far ahead of myself, let\u2019s formalize the role of structured exception handling and check out how it differs from traditional error-handling techniques.<br \/>\n\u5728 .NET \u547d\u540d\u6cd5\u4e2d\uff0c\u5f02\u5e38\u4f1a\u8003\u8651\u9519\u8bef\u3001\u865a\u5047\u7528\u6237\u8f93\u5165\u548c\u8fd0\u884c\u65f6\u9519\u8bef\uff0c\u5373\u4f7f\u7a0b\u5e8f\u5458\u53ef\u80fd\u5c06\u5176\u4e2d\u6bcf\u4e2a\u9519\u8bef\u89c6\u4e3a\u4e00\u4e2a\u5355\u72ec\u7684\u95ee\u9898\u3002\u4f46\u662f\uff0c\u5728\u6211\u8d70\u5f97\u592a\u8fdc\u4e4b\u524d\uff0c\u8ba9\u6211\u4eec\u6b63\u5f0f\u5b9a\u4e49\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u7684\u89d2\u8272\uff0c\u5e76\u68c0\u67e5\u5b83\u4e0e\u4f20\u7edf\u7684\u9519\u8bef\u5904\u7406\u6280\u672f\u6709\u4f55\u4e0d\u540c\u3002<\/p>\n<p>\u25a0 Note To make the code examples used in this book as clean as possible, I will not catch every possible exception that may be thrown by a given method in the base class libraries. In your production-level projects, you should, of course, make liberal use of the techniques presented in this chapter.<br \/>\n\u6ce8\u610f \u4e3a\u4e86\u4f7f\u672c\u4e66\u4e2d\u4f7f\u7528\u7684\u4ee3\u7801\u793a\u4f8b\u5c3d\u53ef\u80fd\u5e72\u51c0\uff0c\u6211\u4e0d\u4f1a\u6355\u83b7\u57fa\u7c7b\u5e93\u4e2d\u7ed9\u5b9a\u65b9\u6cd5\u53ef\u80fd\u5f15\u53d1\u7684\u6240\u6709\u53ef\u80fd\u7684\u5f02\u5e38\u3002\u5f53\u7136\uff0c\u5728\u60a8\u7684\u751f\u4ea7\u7ea7\u9879\u76ee\u4e2d\uff0c\u60a8\u5e94\u8be5\u81ea\u7531\u4f7f\u7528\u672c\u7ae0\u4e2d\u4ecb\u7ecd\u7684\u6280\u672f\u3002<\/p>\n<h2>The Role of .NET Exception Handling<\/h2>\n<p>.NET \u5f02\u5e38\u5904\u7406\u7684\u4f5c\u7528<\/p>\n<p>Prior to .NET, error handling under the Windows operating system was a confused mishmash of techniques. Many programmers rolled their own error-handling logic within the context of a given application. For example, a development team could define a set of numerical constants that represented known error conditions and make use of them as method return values. By way of an example, consider the following partial C code:<br \/>\n\u5728.NET\u4e4b\u524d\uff0cWindows\u64cd\u4f5c\u7cfb\u7edf\u4e0b\u7684\u9519\u8bef\u5904\u7406\u662f\u6280\u672f\u6df7\u4e71\u7684\u5927\u6742\u70e9\u3002\u8bb8\u591a\u7a0b\u5e8f\u5458\u5728\u7ed9\u5b9a\u5e94\u7528\u7a0b\u5e8f\u7684\u4e0a\u4e0b\u6587\u4e2d\u5f15\u5165\u4e86\u81ea\u5df1\u7684\u9519\u8bef\u5904\u7406\u903b\u8f91\u3002\u4f8b\u5982\uff0c\u5f00\u53d1\u56e2\u961f\u53ef\u4ee5\u5b9a\u4e49\u4e00\u7ec4\u8868\u793a\u5df2\u77e5\u9519\u8bef\u6761\u4ef6\u7684\u6570\u503c\u5e38\u91cf\uff0c\u5e76\u5c06\u5176\u7528\u4f5c\u65b9\u6cd5\u8fd4\u56de\u503c\u3002\u4f5c\u4e3a\u793a\u4f8b\uff0c\u8bf7\u8003\u8651\u4ee5\u4e0b\u90e8\u5206 C \u4ee3\u7801\uff1a<\/p>\n<p>\/<em> A very C-style error trapping mechanism. <\/em>\/ #define E_FILENOTFOUND 1000<\/p>\n<p>int UseFileSystem()<br \/>\n{<br \/>\n\/\/ Assume something happens in this function<br \/>\n\/\/ that causes the following return value. return E_FILENOTFOUND;<br \/>\n}<\/p>\n<p>void main()<br \/>\n{<br \/>\nint retVal = UseFileSystem(); if(retVal == E_FILENOTFOUND)<br \/>\nprintf(&quot;Cannot find file...&quot;);<br \/>\n}<\/p>\n<p>This approach is less than ideal, given that the constant E<em>FILENOTFOUND is little more than a numerical value and is far from being a helpful agent regarding how to deal with the problem. Ideally, you would like to wrap the error\u2019s name, a descriptive message, and other helpful information about this error condition into a single, well-defined package (which is exactly what happens under structured exception handling). In addition to a developer\u2019s ad hoc techniques, the Windows API defines hundreds of error codes that come by way of #defines, HRESULTs, and far too many variations on the simple Boolean (bool, BOOL, VARIANT<\/em> BOOL, etc.).<br \/>\n\u8fd9\u79cd\u65b9\u6cd5\u4e0d\u592a\u7406\u60f3\uff0c\u56e0\u4e3a\u5e38\u6570E<em>FILENOTFOUND\u53ea\u4e0d\u8fc7\u662f\u4e00\u4e2a\u6570\u503c\uff0c\u8fdc\u4e0d\u80fd\u6210\u4e3a\u5982\u4f55\u5904\u7406\u95ee\u9898\u7684\u6709\u7528\u4ee3\u7406\u3002\u7406\u60f3\u60c5\u51b5\u4e0b\uff0c\u60a8\u5e0c\u671b\u5c06\u9519\u8bef\u7684\u540d\u79f0\u3001\u63cf\u8ff0\u6027\u6d88\u606f\u548c\u6709\u5173\u6b64\u9519\u8bef\u6761\u4ef6\u7684\u5176\u4ed6\u6709\u7528\u4fe1\u606f\u5305\u88c5\u5230\u5355\u4e2a\u5b9a\u4e49\u660e\u786e\u7684\u5305\u4e2d\uff08\u8fd9\u6b63\u662f\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u4e0b\u53d1\u751f\u7684\u60c5\u51b5\uff09\u3002\u9664\u4e86\u5f00\u53d1\u4eba\u5458\u7684\u4e34\u65f6\u6280\u672f\u4e4b\u5916\uff0cWindows API \u8fd8\u5b9a\u4e49\u4e86\u6570\u767e\u4e2a\u9519\u8bef\u4ee3\u7801\uff0c\u8fd9\u4e9b\u4ee3\u7801\u6765\u81ea #defines\u3001HRESULTs \u4ee5\u53ca\u7b80\u5355\u5e03\u5c14\u503c\uff08bool\u3001BOOL\u3001VARIANT<\/em> BOOL \u7b49\uff09\u7684\u592a\u591a\u53d8\u4f53\u3002<\/p>\n<p>The obvious problem with these older techniques is the tremendous lack of symmetry. Each approach is more or less tailored to a given technology, a given language, and perhaps even a given project. To<br \/>\nput an end to this madness, the .NET platform provides a standard technique to send and trap runtime errors: structured exception handling. The beauty of this approach is that developers now have a unified approach to error handling, which is common to all languages targeting the .NET platform. Therefore, the way in which a C# programmer handles errors is syntactically similar to that of a VB programmer, or a C++ programmer using C++\/CLI.<br \/>\n\u8fd9\u4e9b\u65e7\u6280\u672f\u7684\u660e\u663e\u95ee\u9898\u662f\u4e25\u91cd\u7f3a\u4e4f\u5bf9\u79f0\u6027\u3002\u6bcf\u79cd\u65b9\u6cd5\u90fd\u6216\u591a\u6216\u5c11\u5730\u9488\u5bf9\u7ed9\u5b9a\u7684\u6280\u672f\u3001\u7ed9\u5b9a\u7684\u8bed\u8a00\uff0c\u751a\u81f3\u53ef\u80fd\u662f\u7ed9\u5b9a\u7684\u9879\u76ee\u91cf\u8eab\u5b9a\u5236\u7684\u3002\u81ea\u4e3a\u4e86\u7ed3\u675f\u8fd9\u79cd\u75af\u72c2\uff0c.NET \u5e73\u53f0\u63d0\u4f9b\u4e86\u4e00\u79cd\u53d1\u9001\u548c\u6355\u83b7\u8fd0\u884c\u65f6\u9519\u8bef\u7684\u6807\u51c6\u6280\u672f\uff1a\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u3002\u8fd9\u79cd\u65b9\u6cd5\u7684\u4f18\u70b9\u5728\u4e8e\uff0c\u5f00\u53d1\u4eba\u5458\u73b0\u5728\u5177\u6709\u7edf\u4e00\u7684\u9519\u8bef\u5904\u7406\u65b9\u6cd5\uff0c\u8fd9\u5bf9\u4e8e\u9762\u5411 .NET \u5e73\u53f0\u7684\u6240\u6709\u8bed\u8a00\u90fd\u662f\u901a\u7528\u7684\u3002\u56e0\u6b64\uff0cC# \u7a0b\u5e8f\u5458\u5904\u7406\u9519\u8bef\u7684\u65b9\u5f0f\u5728\u8bed\u6cd5\u4e0a\u7c7b\u4f3c\u4e8e\u4f7f\u7528 C++\/CLI \u7684 VB \u7a0b\u5e8f\u5458\u6216C++\u7a0b\u5e8f\u5458\u3002<\/p>\n<p>As an added bonus, the syntax used to throw and catch exceptions across assemblies and machine boundaries is identical. For example, if you use C# to build a ASP.NET Core RESTful service, you can throw a JSON fault to a remote caller, using the same keywords that allow you to throw an exception between methods in the same application.<br \/>\n\u4f5c\u4e3a\u989d\u5916\u7684\u597d\u5904\uff0c\u7528\u4e8e\u8de8\u7a0b\u5e8f\u96c6\u548c\u8ba1\u7b97\u673a\u8fb9\u754c\u5f15\u53d1\u548c\u6355\u83b7\u5f02\u5e38\u7684\u8bed\u6cd5\u662f\u76f8\u540c\u7684\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f7f\u7528 C# \u751f\u6210 ASP.NET \u6838\u5fc3 RESTful \u670d\u52a1\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528\u5141\u8bb8\u5728\u540c\u4e00\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u65b9\u6cd5\u4e4b\u95f4\u5f15\u53d1\u5f02\u5e38\u7684\u76f8\u540c\u5173\u952e\u5b57\uff0c\u5c06 JSON \u9519\u8bef\u629b\u7ed9\u8fdc\u7a0b\u8c03\u7528\u65b9\u3002<\/p>\n<p>Another bonus of .NET exceptions is that rather than receiving a cryptic numerical value, exceptions are objects that contain a human-readable description of the problem, as well as a detailed snapshot of the call stack that triggered the exception in the first place. Furthermore, you are able to give the end user help-link information that points the user to a URL that provides details about the error, as well as custom programmer-defined data.<br \/>\n\u4f5c\u4e3a\u989d\u5916\u7684\u597d\u5904\uff0c\u7528\u4e8e\u8de8\u7a0b\u5e8f\u96c6\u548c\u8ba1\u7b97\u673a\u8fb9\u754c\u5f15\u53d1\u548c\u6355\u83b7\u5f02\u5e38\u7684\u8bed\u6cd5\u662f\u76f8\u540c\u7684\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f7f\u7528 C# \u751f\u6210 ASP.NET \u6838\u5fc3 RESTful \u670d\u52a1\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528\u5141\u8bb8\u5728\u540c\u4e00\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u65b9\u6cd5\u4e4b\u95f4\u5f15\u53d1\u5f02\u5e38\u7684\u76f8\u540c\u5173\u952e\u5b57\uff0c\u5c06 JSON \u9519\u8bef\u629b\u7ed9\u8fdc\u7a0b\u8c03\u7528\u65b9\u3002<\/p>\n<h2>The Building Blocks of .NET Exception Handling<\/h2>\n<p>.NET \u5f02\u5e38\u5904\u7406\u7684\u6784\u5efa\u57fa\u5757<\/p>\n<p>Programming with structured exception handling involves the use of four interrelated entities.<br \/>\n\u4f7f\u7528\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u8fdb\u884c\u7f16\u7a0b\u6d89\u53ca\u4f7f\u7528\u56db\u4e2a\u76f8\u4e92\u5173\u8054\u7684\u5b9e\u4f53\u3002<\/p>\n<p>\u2022A class type that represents the details of the exception<br \/>\n\u8868\u793a\u5f02\u5e38\u8be6\u7ec6\u4fe1\u606f\u7684\u7c7b\u7c7b\u578b<br \/>\n\u2022A member that throws an instance of the exception class to the caller under the correct circumstances<br \/>\n\u5728\u6b63\u786e\u60c5\u51b5\u4e0b\u5c06\u5f02\u5e38\u7c7b\u7684\u5b9e\u4f8b\u629b\u7ed9\u8c03\u7528\u65b9\u7684\u6210\u5458<br \/>\n\u2022A block of code on the caller\u2019s side that invokes the exception-prone member<br \/>\n\u8c03\u7528\u65b9\u7aef\u8c03\u7528\u5bb9\u6613\u53d1\u751f\u5f02\u5e38\u7684\u6210\u5458\u7684\u4ee3\u7801\u5757<br \/>\n\u2022A block of code on the caller\u2019s side that will process (or catch) the exception, should it occur<br \/>\n\u8c03\u7528\u65b9\u7aef\u7684\u4ee3\u7801\u5757\uff0c\u5982\u679c\u53d1\u751f\u5f02\u5e38\uff0c\u5b83\u5c06\u5904\u7406\uff08\u6216\u6355\u83b7\uff09\u5f02\u5e38<\/p>\n<p>The C# programming language offers five keywords (try, catch, throw, finally, and when) that allow you to throw and handle exceptions. The object that represents the problem at hand is a class extending System.Exception (or a descendent thereof). Given this fact, let\u2019s check out the role of this exception-centric base class.<br \/>\nC# \u7f16\u7a0b\u8bed\u8a00\u63d0\u4f9b\u4e86\u4e94\u4e2a\u5173\u952e\u5b57\uff08try\u3001catch\u3001throw \u3001finally \u548c when\uff09\uff0c\u53ef\u7528\u4e8e\u5f15\u53d1\u548c\u5904\u7406\u5f02\u5e38\u3002\u8868\u793a\u624b\u5934\u95ee\u9898\u7684\u5bf9\u8c61\u662f\u4e00\u4e2a\u6269\u5c55 System.Exception \u7684\u7c7b\uff08\u6216\u5176\u540e\u4ee3\uff09\u3002\u9274\u4e8e\u8fd9\u4e00\u4e8b\u5b9e\uff0c\u8ba9\u6211\u4eec\u770b\u770b\u8fd9\u4e2a\u4ee5\u5f02\u5e38\u4e3a\u4e2d\u5fc3\u7684\u57fa\u7c7b\u7684\u4f5c\u7528\u3002<\/p>\n<h2>The System.Exception Base Class<\/h2>\n<p>System.Exception \u57fa\u7c7b<\/p>\n<p>All exceptions ultimately derive from the System.Exception base class, which in turn derives from System. Object. Here is the main definition of this class (note that some of these members are virtual and may thus be overridden by derived classes):<br \/>\n\u6240\u6709\u5f02\u5e38\u6700\u7ec8\u90fd\u6d3e\u751f\u81ea System.Exception \u57fa\u7c7b\uff0c\u800c\u57fa\u7c7b\u53c8\u6d3e\u751f\u81ea System\u3002\u5bf9\u8c61\u3002\u4e0b\u9762\u662f\u6b64\u7c7b\u7684\u4e3b\u8981\u5b9a\u4e49\uff08\u8bf7\u6ce8\u610f\uff0c\u5176\u4e2d\u4e00\u4e9b\u6210\u5458\u662f\u865a\u62df\u7684\uff0c\u56e0\u6b64\u53ef\u80fd\u88ab\u6d3e\u751f\u7c7b\u8986\u76d6\uff09\uff1a<\/p>\n<p>public class Exception : ISerializable<br \/>\n{<br \/>\n\/\/ Public constructors<br \/>\npublic Exception(string message, Exception innerException); public Exception(string message);<br \/>\npublic Exception();<br \/>\n...<br \/>\n\/\/ Methods<br \/>\npublic virtual Exception GetBaseException();<br \/>\npublic virtual void GetObjectData(SerializationInfo info, StreamingContext context);<\/p>\n<p>\/\/ Properties<br \/>\npublic virtual IDictionary Data { get; } public virtual string HelpLink { get; set; } public int HResult {get;set;}<br \/>\npublic Exception InnerException { get; } public virtual string Message { get; } public virtual string Source { get; set; } public virtual string StackTrace { get; } public MethodBase TargetSite { get; }<br \/>\n}<\/p>\n<p>As you can see, many of the properties defined by System.Exception are read-only in nature. This is because derived types will typically supply default values for each property. For example, the default message of the IndexOutOfRangeException type is \u201cIndex was outside the bounds of the array.\u201d<br \/>\n\u5982\u60a8\u6240\u89c1\uff0cSystem.Exception \u5b9a\u4e49\u7684\u8bb8\u591a\u5c5e\u6027\u672c\u8d28\u4e0a\u90fd\u662f\u53ea\u8bfb\u7684\u3002\u8fd9\u662f\u56e0\u4e3a\u6d3e\u751f\u7c7b\u578b\u901a\u5e38\u4f1a\u4e3a\u6bcf\u4e2a\u5c5e\u6027\u63d0\u4f9b\u9ed8\u8ba4\u503c\u3002\u4f8b\u5982\uff0cIndexOutOfRangeException \u7c7b\u578b\u7684\u9ed8\u8ba4\u6d88\u606f\u662f\u201c\u7d22\u5f15\u8d85\u51fa\u6570\u7ec4\u7684\u8fb9\u754c\u201d\u3002<\/p>\n<p>Table 7-1 describes the most important members of System.Exception.<br \/>\n\u8868 7-1 \u63cf\u8ff0\u4e86 System.Exception \u6700\u91cd\u8981\u7684\u6210\u5458\u3002<\/p>\n<p>Table 7-1. Core Members of the System.Exception Type<br \/>\n\u8868 7-1. \u7cfb\u7edf\u7684\u6838\u5fc3\u6210\u5458\u3002\u5f02\u5e38\u7c7b\u578b<\/p>\n<table>\n<tr>\n<td>System.Exception Property<\/td>\n<td>Meaning in Life<\/td>\n<\/tr>\n<tr>\n<td>Data<\/td>\n<td>This read-only property retrieves a collection of key-value pairs (represented by an object implementing\u00a0IDictionary) that provide additional, programmer-defined information about the exception. By default, this collection is empty.<br \/>\n        \u6b64\u53ea\u8bfb\u5c5e\u6027\u68c0\u7d22\u952e\u503c\u5bf9\u7684\u96c6\u5408\uff08\u7531\u5b9e\u73b0 IDictionary \u7684\u5bf9\u8c61\u8868\u793a\uff09\uff0c\u8fd9\u4e9b\u952e\u503c\u5bf9\u63d0\u4f9b\u6709\u5173\u5f02\u5e38\u7684\u5176\u4ed6\u7a0b\u5e8f\u5458\u5b9a\u4e49\u7684\u4fe1\u606f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6b64\u96c6\u5408\u4e3a\u7a7a\u3002<\/td>\n<\/tr>\n<tr>\n<td>HelpLink<\/td>\n<td>This property gets or sets a URL to a help file or website describing the error in full detail.<br \/>\n        \u6b64\u5c5e\u6027\u83b7\u53d6\u6216\u8bbe\u7f6e\u6307\u5411\u5e2e\u52a9\u6587\u4ef6\u6216\u7f51\u7ad9\u7684 URL\uff0c\u4ee5\u5b8c\u6574\u8be6\u7ec6\u63cf\u8ff0\u9519\u8bef\u3002<\/td>\n<\/tr>\n<tr>\n<td>InnerException<\/td>\n<td>This read-only property can be used to obtain information about the previous exceptions that caused the current exception to occur. The previous exceptions are recorded by passing them into the constructor of the most current exception.<br \/>\n        \u6b64\u53ea\u8bfb\u5c5e\u6027\u53ef\u7528\u4e8e\u83b7\u53d6\u6709\u5173\u5bfc\u81f4\u5f53\u524d\u5f02\u5e38\u53d1\u751f\u7684\u5148\u524d\u5f02\u5e38\u7684\u4fe1\u606f\u3002\u901a\u8fc7\u5c06\u4ee5\u524d\u7684\u5f02\u5e38\u4f20\u9012\u5230\u6700\u65b0\u5f02\u5e38\u7684\u6784\u9020\u51fd\u6570\u4e2d\u6765\u8bb0\u5f55\u5b83\u4eec\u3002<\/td>\n<\/tr>\n<tr>\n<td>Message<\/td>\n<td>This read-only property returns the textual description of a given error. The error message itself is set as a constructor parameter.<br \/>\n        \u6b64\u53ea\u8bfb\u5c5e\u6027\u8fd4\u56de\u7ed9\u5b9a\u9519\u8bef\u7684\u6587\u672c\u8bf4\u660e\u3002\u9519\u8bef\u6d88\u606f\u672c\u8eab\u8bbe\u7f6e\u4e3a\u6784\u9020\u51fd\u6570\u53c2\u6570\u3002<\/td>\n<\/tr>\n<tr>\n<td>Source<\/td>\n<td>This property gets or sets the name of the assembly, or the object, that threw the current exception.<br \/>\n        \u6b64\u5c5e\u6027\u83b7\u53d6\u6216\u8bbe\u7f6e\u5f15\u53d1\u5f53\u524d\u5f02\u5e38\u7684\u7a0b\u5e8f\u96c6\u6216\u5bf9\u8c61\u7684\u540d\u79f0\u3002<\/td>\n<\/tr>\n<tr>\n<td>StackTrace<\/td>\n<td>This read-only property contains a string that identifies the sequence of calls that triggered the exception. As you might guess, this property is useful during debugging or if you want to dump the error to an external error log.<br \/>\n        \u6b64\u53ea\u8bfb\u5c5e\u6027\u5305\u542b\u4e00\u4e2a\u5b57\u7b26\u4e32\uff0c\u7528\u4e8e\u6807\u8bc6\u89e6\u53d1\u5f02\u5e38\u7684\u8c03\u7528\u5e8f\u5217\u3002\u6b63\u5982\u60a8\u53ef\u80fd\u731c\u5230\u7684\u90a3\u6837\uff0c\u6b64\u5c5e\u6027\u5728\u8c03\u8bd5\u671f\u95f4\u5f88\u6709\u7528\uff0c\u6216\u8005\u5982\u679c\u8981\u5c06\u9519\u8bef\u8f6c\u50a8\u5230\u5916\u90e8\u9519\u8bef\u65e5\u5fd7\u4e2d\u3002<\/td>\n<\/tr>\n<tr>\n<td>TargetSite<\/td>\n<td>This read-only property returns a\u00a0MethodBase\u00a0object, which describes numerous details about the method that threw the exception (invoking\u00a0ToString()\u00a0will identify the method by name).<br \/>\n        \u6b64\u53ea\u8bfb\u5c5e\u6027\u8fd4\u56de\u4e00\u4e2a MethodBase \u5bf9\u8c61\uff0c\u8be5\u5bf9\u8c61\u63cf\u8ff0\u4e86\u6709\u5173\u5f15\u53d1\u5f02\u5e38\u7684\u65b9\u6cd5\u7684\u5927\u91cf\u8be6\u7ec6\u4fe1\u606f\uff08\u8c03\u7528 ToString\uff08\uff09 \u5c06\u6309\u540d\u79f0\u6807\u8bc6\u8be5\u65b9\u6cd5\uff09\u3002<\/td>\n<\/tr>\n<\/table>\n<h2>The Simplest Possible Example<\/h2>\n<p>\u6700\u7b80\u5355\u7684\u4f8b\u5b50<\/p>\n<p>To illustrate the usefulness of structured exception handling, you need to create a class that will throw an exception under the correct (or one might say exceptional) circumstances. Assume you have created a new C# Console Application project (named SimpleException) that defines two class types (Car and Radio)<br \/>\n\u4e3a\u4e86\u8bf4\u660e\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u7684\u6709\u7528\u6027\uff0c\u60a8\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u7c7b\uff0c\u8be5\u7c7b\u5c06\u5728\u6b63\u786e\uff08\u6216\u53ef\u4ee5\u8bf4\u662f\u5f02\u5e38\uff09\u60c5\u51b5\u4e0b\u5f15\u53d1\u5f02\u5e38\u3002\u5047\u8bbe\u60a8\u5df2\u7ecf\u521b\u5efa\u4e86\u4e00\u4e2a\u65b0\u7684 C# \u63a7\u5236\u53f0\u5e94\u7528\u7a0b\u5e8f\u9879\u76ee\uff08\u540d\u4e3a SimpleException\uff09\uff0c\u8be5\u9879\u76ee\u5b9a\u4e49\u4e86\u4e24\u79cd\u7c7b\u7c7b\u578b\uff08\u6c7d\u8f66\u548c\u6536\u97f3\u673a\uff09\u3002)<\/p>\n<p>associated by the \u201chas-a\u201d relationship. The Radio type defines a single method that turns the radio\u2019s power on or off.<br \/>\n\u4e0e\u201cHAS-A\u201d\u5173\u7cfb\u76f8\u5173\u8054\u3002Radio \u7c7b\u578b\u5b9a\u4e49\u6253\u5f00\u6216\u5173\u95ed\u65e0\u7ebf\u7535\u7535\u6e90\u7684\u5355\u4e2a\u65b9\u6cd5\u3002<\/p>\n<p>namespace SimpleException; class Radio<br \/>\n{<br \/>\npublic void TurnOn(bool on)<br \/>\n{<br \/>\nConsole.WriteLine(on ? &quot;Jamming...&quot; : &quot;Quiet time...&quot;);<br \/>\n}<br \/>\n}<\/p>\n<p>In addition to leveraging the Radio class via containment\/delegation, the Car class (shown next) is defined in such a way that if the user accelerates a Car object beyond a predefined maximum speed (specified using a constant member variable named MaxSpeed), its engine explodes, rendering the Car unusable (captured by a private bool member variable named _carIsDead).<br \/>\n\u9664\u4e86\u901a\u8fc7\u5305\u542b\/\u59d4\u6d3e\u5229\u7528 Radio \u7c7b\u4e4b\u5916\uff0cCar \u7c7b\uff08\u5982\u4e0b\u6240\u793a\uff09\u7684\u5b9a\u4e49\u65b9\u5f0f\u662f\uff0c\u5982\u679c\u7528\u6237\u5c06 Car \u5bf9\u8c61\u52a0\u901f\u5230\u8d85\u8fc7\u9884\u5b9a\u4e49\u7684\u6700\u5927\u901f\u5ea6\uff08\u4f7f\u7528\u540d\u4e3a MaxSpeed \u7684\u5e38\u91cf\u6210\u5458\u53d8\u91cf\u6307\u5b9a\uff09\uff0c\u5176\u5f15\u64ce\u5c06\u7206\u70b8\uff0c\u4f7f Car \u4e0d\u53ef\u7528\uff08\u7531\u540d\u4e3a _carIsDead \u7684\u79c1\u6709\u5e03\u5c14\u6210\u5458\u53d8\u91cf\u6355\u83b7\uff09\u3002<\/p>\n<p>Beyond these points, the Car type has a few properties to represent the current speed and a user- supplied \u201cpet name,\u201d as well as various constructors to set the state of a new Car object. Here is the complete definition (with code comments):<br \/>\n\u9664\u4e86\u8fd9\u4e9b\u70b9\u4e4b\u5916\uff0cCar \u7c7b\u578b\u8fd8\u6709\u4e00\u4e9b\u5c5e\u6027\u6765\u8868\u793a\u5f53\u524d\u901f\u5ea6\u548c\u7528\u6237\u63d0\u4f9b\u7684\u201c\u5ba0\u7269\u540d\u79f0\u201d\uff0c\u4ee5\u53ca\u7528\u4e8e\u8bbe\u7f6e\u65b0 Car \u5bf9\u8c61\u72b6\u6001\u7684\u5404\u79cd\u6784\u9020\u51fd\u6570\u3002\u4ee5\u4e0b\u662f\u5b8c\u6574\u7684\u5b9a\u4e49\uff08\u5e26\u6709\u4ee3\u7801\u6ce8\u91ca\uff09\uff1a<\/p>\n<p>namespace SimpleException; class Car<br \/>\n{<br \/>\n\/\/ Constant for maximum speed. public const int MaxSpeed = 100;<\/p>\n<p>\/\/ Car properties.<br \/>\npublic int CurrentSpeed {get; set;} = 0; public string PetName {get; set;} = &quot;&quot;;<\/p>\n<p>\/\/ Is the car still operational? private bool _carIsDead;<\/p>\n<p>\/\/ A car has-a radio.<br \/>\nprivate readonly Radio _theMusicBox = new Radio();<\/p>\n<p>\/\/ Constructors. public Car() {}<br \/>\npublic Car(string name, int speed)<br \/>\n{<br \/>\nCurrentSpeed = speed;<br \/>\nPetName = name;<br \/>\n}<\/p>\n<p>public void CrankTunes(bool state)<br \/>\n{<br \/>\n\/\/ Delegate request to inner object.<br \/>\n_theMusicBox.TurnOn(state);<br \/>\n}<\/p>\n<p>\/\/ See if Car has overheated.<\/p>\n<p>public void Accelerate(int delta)<br \/>\n{<br \/>\nif (_carIsDead)<br \/>\n{<br \/>\nConsole.WriteLine(&quot;{0} is out of order...&quot;, PetName);<br \/>\n}<br \/>\nelse<br \/>\n{<br \/>\nCurrentSpeed += delta;<br \/>\nif (CurrentSpeed &gt; MaxSpeed)<br \/>\n{<br \/>\nConsole.WriteLine(&quot;{0} has overheated!&quot;, PetName); CurrentSpeed = 0;<br \/>\n_carIsDead = true;<br \/>\n}<br \/>\nelse<br \/>\n{<br \/>\nConsole.WriteLine(&quot;=&gt; CurrentSpeed = {0}&quot;, CurrentSpeed);<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>Next, update your Program.cs file to force a Car object to exceed the predefined maximum speed (set to 100, in the Car class), as shown here:<br \/>\n\u63a5\u4e0b\u6765\uff0c\u66f4\u65b0 Program.cs \u6587\u4ef6\u4ee5\u5f3a\u5236 Car \u5bf9\u8c61\u8d85\u8fc7\u9884\u5b9a\u4e49\u7684\u6700\u5927\u901f\u5ea6\uff08\u5728 Car \u7c7b\u4e2d\u8bbe\u7f6e\u4e3a 100\uff09\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<p>using System.Collections; using SimpleException;<\/p>\n<p>Console.WriteLine(&quot;<strong><strong><em> Simple Exception Example <\/em><\/strong><\/strong>&quot;); Console.WriteLine(&quot;=&gt; Creating a car and stepping on it!&quot;); Car myCar = new Car(&quot;Zippy&quot;, 20);<br \/>\nmyCar.CrankTunes(true);<\/p>\n<p>for (int i = 0; i &lt; 10; i++)<br \/>\n{<br \/>\nmyCar.Accelerate(10);<br \/>\n}<br \/>\nConsole.ReadLine();<\/p>\n<p>When executing the code, you would see the following output:<br \/>\n\u6267\u884c\u4ee3\u7801\u65f6\uff0c\u60a8\u5c06\u770b\u5230\u4ee5\u4e0b\u8f93\u51fa\uff1a<\/p>\n<p><strong><strong><em> Simple Exception Example <\/em><\/strong><\/strong><br \/>\n=&gt; Creating a car and stepping on it! Jamming...<br \/>\n=&gt; CurrentSpeed = 30<br \/>\n=&gt; CurrentSpeed = 40<br \/>\n=&gt; CurrentSpeed = 50<br \/>\n=&gt; CurrentSpeed = 60<\/p>\n<p>=&gt; CurrentSpeed = 70<br \/>\n=&gt; CurrentSpeed = 80<br \/>\n=&gt; CurrentSpeed = 90<br \/>\n=&gt; CurrentSpeed = 100 Zippy has overheated! Zippy is out of order...<\/p>\n<h2>Throwing a General Exception<\/h2>\n<p>\u5f15\u53d1\u5e38\u89c4\u5f02\u5e38<\/p>\n<p>Now that you have a functional Car class, I\u2019ll demonstrate the simplest way to throw an exception. The current implementation of Accelerate() simply displays an error message if the caller attempts to speed up the Car beyond its upper limit.<br \/>\n\u73b0\u5728\u4f60\u6709\u4e00\u4e2a\u51fd\u6570\u5f0f Car \u7c7b\uff0c\u6211\u5c06\u6f14\u793a\u5f15\u53d1\u5f02\u5e38\u7684\u6700\u7b80\u5355\u65b9\u6cd5\u3002Accelerate\uff08\uff09 \u7684\u5f53\u524d\u5b9e\u73b0\u53ea\u662f\u5728\u8c03\u7528\u65b9\u5c1d\u8bd5\u5c06 Car \u52a0\u901f\u5230\u8d85\u51fa\u5176\u4e0a\u9650\u65f6\u663e\u793a\u9519\u8bef\u6d88\u606f\u3002<\/p>\n<p>To retrofit this method to throw an exception if the user attempts to speed up the automobile after it has met its maker, you want to create and configure a new instance of the System.Exception class, setting the value of the read-only Message property via the class constructor. When you want to send the exception object back to the caller, use the C# throw() statement. Here is the relevant code update to the<br \/>\nAccelerate() method:<br \/>\n\u82e5\u8981\u6539\u9020\u6b64\u65b9\u6cd5\uff0c\u4ee5\u4fbf\u5728\u7528\u6237\u9047\u5230\u5176\u5236\u9020\u5546\u540e\u5c1d\u8bd5\u52a0\u901f\u6c7d\u8f66\u65f6\u5f15\u53d1\u5f02\u5e38\uff0c\u60a8\u9700\u8981\u521b\u5efa\u548c\u914d\u7f6e System.Exception \u7c7b\u7684\u65b0\u5b9e\u4f8b\uff0c\u901a\u8fc7\u7c7b\u6784\u9020\u51fd\u6570\u8bbe\u7f6e\u53ea\u8bfb Message \u5c5e\u6027\u7684\u503c\u3002\u5f53\u60a8\u8981\u53d1\u9001\u5f02\u5e38\u5bf9\u8c61\u56de\u5230\u8c03\u7528\u65b9\uff0c\u4f7f\u7528 C# throw\uff08\uff09 \u8bed\u53e5\u3002\u4ee5\u4e0b\u662f\u5bf9\u52a0\u901f\uff08\uff09 \u65b9\u6cd5\uff1a<\/p>\n<p>\/\/ This time, throw an exception if the user speeds up beyond MaxSpeed. public void Accelerate(int delta)<br \/>\n{<br \/>\nif (_carIsDead)<br \/>\n{<br \/>\nConsole.WriteLine(&quot;{0} is out of order...&quot;, PetName);<br \/>\n}<br \/>\nelse<br \/>\n{<br \/>\nCurrentSpeed += delta;<br \/>\nif (CurrentSpeed &gt;= MaxSpeed)<br \/>\n{<br \/>\nCurrentSpeed = 0;<br \/>\n_carIsDead = true;<\/p>\n<p>\/\/ Use the &quot;throw&quot; keyword to raise an exception. throw new Exception($&quot;{PetName} has overheated!&quot;);<br \/>\n}<br \/>\nConsole.WriteLine(&quot;=&gt; CurrentSpeed = {0}&quot;, CurrentSpeed);<br \/>\n}<br \/>\n}<\/p>\n<p>Before examining how a caller would catch this exception, let\u2019s look at a few points of interest. First, when you are throwing an exception, it is always up to you to decide exactly what constitutes the error in question and when an exception should be thrown. Here, you are making the assumption that if the program attempts to increase the speed of a Car object beyond the maximum, a System.Exception object should be thrown to indicate the Accelerate() method cannot continue (which may or may not be a valid assumption; this will be a judgment call on your part based on the application you are creating).<br \/>\n\u82e5\u8981\u6539\u9020\u6b64\u65b9\u6cd5\uff0c\u4ee5\u4fbf\u5728\u7528\u6237\u9047\u5230\u5176\u5236\u9020\u5546\u540e\u5c1d\u8bd5\u52a0\u901f\u6c7d\u8f66\u65f6\u5f15\u53d1\u5f02\u5e38\uff0c\u60a8\u9700\u8981\u521b\u5efa\u548c\u914d\u7f6e System.Exception \u7c7b\u7684\u65b0\u5b9e\u4f8b\uff0c\u901a\u8fc7\u7c7b\u6784\u9020\u51fd\u6570\u8bbe\u7f6e\u53ea\u8bfb Message \u5c5e\u6027\u7684\u503c\u3002\u5f53\u60a8\u8981\u53d1\u9001\u5f02\u5e38\u5bf9\u8c61\u56de\u5230\u8c03\u7528\u65b9\uff0c\u4f7f\u7528 C# throw\uff08\uff09 \u8bed\u53e5\u3002\u4ee5\u4e0b\u662f\u5bf9\u52a0\u901f\uff08\uff09 \u65b9\u6cd5\uff1a<\/p>\n<p>Alternatively, you could implement Accelerate() to recover automatically without needing to throw an exception in the first place. By and large, exceptions should be thrown only when a more terminal condition has been met (e.g., not finding a necessary file, failing to connect to a database, and the like) and not used as a logic flow mechanism. Deciding exactly what justifies throwing an exception is a design issue you must always contend with. For the current purposes, assume that asking a doomed automobile to increase its speed is cause to throw an exception.<br \/>\n\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u5b9e\u73b0 Accelerate\uff08\uff09 \u81ea\u52a8\u6062\u590d\uff0c\u800c\u65e0\u9700\u9996\u5148\u629b\u51fa\u5f02\u5e38\u3002\u603b\u7684\u6765\u8bf4\uff0c\u53ea\u6709\u5f53\u6ee1\u8db3\u66f4\u7ec8\u7aef\u7684\u6761\u4ef6\uff08\u4f8b\u5982\uff0c\u627e\u4e0d\u5230\u5fc5\u8981\u7684\u6587\u4ef6\u3001\u65e0\u6cd5\u8fde\u63a5\u5230\u6570\u636e\u5e93\u7b49\uff09\u5e76\u4e14\u4e0d\u4f7f\u7528\u65f6\uff0c\u624d\u5e94\u8be5\u629b\u51fa\u5f02\u5e38\u3002\u4f5c\u4e3a\u4e00\u79cd\u903b\u8f91\u6d41\u673a\u5236\u3002\u786e\u5b9a\u5f15\u53d1\u5f02\u5e38\u7684\u786e\u5207\u7406\u7531\u662f\u60a8\u5fc5\u987b\u59cb\u7ec8\u5e94\u5bf9\u7684\u8bbe\u8ba1\u95ee\u9898\u3002\u51fa\u4e8e\u5f53\u524d\u76ee\u7684\uff0c\u5047\u8bbe\u8981\u6c42\u6ce8\u5b9a\u8981\u5931\u8d25\u7684\u6c7d\u8f66\u63d0\u9ad8\u901f\u5ea6\u4f1a\u5bfc\u81f4\u5f15\u53d1\u5f02\u5e38\u3002<\/p>\n<p>Second, notice how the final else was removed from the method. When an exception is thrown (either by the framework or by manually using a throw() statement), control is returned to the calling method (or by the catch block in a try catch). This eliminates the need for the final else. Whether you leave it in for readability is up to you and your coding standards.<br \/>\n\u5176\u6b21\uff0c\u8bf7\u6ce8\u610f\u6700\u7ec8\u7684 else \u662f\u5982\u4f55\u4ece\u65b9\u6cd5\u4e2d\u5220\u9664\u7684\u3002\u5f53\u5f15\u53d1\u5f02\u5e38\u65f6\uff08\u7531\u6846\u67b6\u6216\u624b\u52a8\u4f7f\u7528 throw\uff08\uff09 \u8bed\u53e5\uff09\uff0c\u63a7\u5236\u6743\u5c06\u8fd4\u56de\u5230\u8c03\u7528\u65b9\u6cd5\uff08\u6216\u7531 try catch \u4e2d\u7684 catch \u5757\uff09\u3002\u8fd9\u6d88\u9664\u4e86\u5bf9\u6700\u7ec8\u5176\u4ed6\u7684\u9700\u8981\u3002\u662f\u5426\u5c06\u5176\u4fdd\u7559\u4e3a\u53ef\u8bfb\u6027\u53d6\u51b3\u4e8e\u60a8\u548c\u60a8\u7684\u7f16\u7801\u6807\u51c6\u3002<\/p>\n<p>In any case, if you were to rerun the application at this point using the previous logic in the top-level statements, the exception would eventually be thrown. As shown in the following output, the result of not handling this error is less than ideal, given you receive a verbose error dump followed by the program\u2019s termination (with your specific file path and line numbers):<br \/>\n\u65e0\u8bba\u5982\u4f55\uff0c\u5982\u679c\u6b64\u65f6\u8981\u4f7f\u7528\u9876\u7ea7\u8bed\u53e5\u4e2d\u7684\u5148\u524d\u903b\u8f91\u91cd\u65b0\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u6700\u7ec8\u5c06\u5f15\u53d1\u5f02\u5e38\u3002\u5982\u4ee5\u4e0b\u8f93\u51fa\u6240\u793a\uff0c\u4e0d\u5904\u7406\u6b64\u9519\u8bef\u7684\u7ed3\u679c\u4e0d\u592a\u7406\u60f3\uff0c\u56e0\u4e3a\u60a8\u4f1a\u6536\u5230\u4e00\u4e2a\u8be6\u7ec6\u7684\u9519\u8bef\u8f6c\u50a8\uff0c\u7136\u540e\u662f\u7a0b\u5e8f\u7684\u7ec8\u6b62\uff08\u4f7f\u7528\u60a8\u7684\u7279\u5b9a\u6587\u4ef6\u8def\u5f84\u548c\u884c\u53f7\uff09\uff1a<\/p>\n<p><strong><strong><em> Simple Exception Example <\/em><\/strong><\/strong><br \/>\n=&gt; Creating a car and stepping on it! Jamming...<br \/>\n=&gt; CurrentSpeed = 30<br \/>\n=&gt; CurrentSpeed = 40<br \/>\n=&gt; CurrentSpeed = 50<br \/>\n=&gt; CurrentSpeed = 60<br \/>\n=&gt; CurrentSpeed = 70<br \/>\n=&gt; CurrentSpeed = 80<br \/>\n=&gt; CurrentSpeed = 90<br \/>\n=&gt; CurrentSpeed = 100<\/p>\n<p>Unhandled exception. System.Exception: Zippy has overheated!<br \/>\nat SimpleException.Car.Accelerate(Int32 delta) in [path to file]\\Car.cs:line 52<br \/>\nat SimpleException.Program.Main(String[] args) in [path to file]\\Program.cs:line 16<\/p>\n<h2>Catching Exceptions<\/h2>\n<p>\u6355\u83b7\u5f02\u5e38<\/p>\n<p>\u25a0 Note  For those coming to C# from a Java background, understand that type members are not prototyped with the set of exceptions they may throw (in other words, .neT Core does not support checked exceptions). For better or for worse, you are not required to handle every exception thrown from a given member.<br \/>\n\u6ce8\u610f \u5bf9\u4e8e\u90a3\u4e9b\u4ece Java \u80cc\u666f\u6765\u5230 C# \u7684\u4eba\uff0c\u8bf7\u4e86\u89e3\u7c7b\u578b\u6210\u5458\u4e0d\u662f\u4f7f\u7528\u5b83\u4eec\u53ef\u80fd\u5f15\u53d1\u7684\u5f02\u5e38\u96c6\u8fdb\u884c\u539f\u578b\u8bbe\u8ba1\u7684\uff08\u6362\u53e5\u8bdd\u8bf4\uff0c.neT Core \u4e0d\u652f\u6301\u68c0\u67e5\u5f02\u5e38\uff09\u3002\u65e0\u8bba\u597d\u574f\uff0c\u60a8\u90fd\u4e0d\u9700\u8981\u5904\u7406\u4ece\u7ed9\u5b9a\u6210\u5458\u5f15\u53d1\u7684\u6bcf\u4e2a\u5f02\u5e38\u3002<\/p>\n<p>Because the Accelerate() method now throws an exception, the caller needs to be ready to handle the exception, should it occur. When you are invoking a method that may throw an exception, you make use of a try\/catch block. After you have caught the exception object, you are able to invoke the members of the exception object to extract the details of the problem.<br \/>\n\u7531\u4e8e Accelerate\uff08\uff09 \u65b9\u6cd5\u73b0\u5728\u629b\u51fa\u5f02\u5e38\uff0c\u56e0\u6b64\u8c03\u7528\u65b9\u9700\u8981\u51c6\u5907\u597d\u5728\u5f02\u5e38\u53d1\u751f\u65f6\u5904\u7406\u5f02\u5e38\u3002\u5f53\u60a8\u8c03\u7528\u53ef\u80fd\u5f15\u53d1\u5f02\u5e38\u7684\u65b9\u6cd5\u65f6\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 try\/catch \u5757\u3002\u6355\u83b7\u5f02\u5e38\u5bf9\u8c61\u540e\uff0c\u53ef\u4ee5\u8c03\u7528\u5f02\u5e38\u5bf9\u8c61\u7684\u6210\u5458\u6765\u63d0\u53d6\u95ee\u9898\u7684\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>What you do with this data is largely up to you. You might want to log this information to a report file, write the data to the event log, email a system administrator, or display the problem to the end user. Here, you will simply dump the contents to the console window:<br \/>\n\u5982\u4f55\u5904\u7406\u8fd9\u4e9b\u6570\u636e\u5728\u5f88\u5927\u7a0b\u5ea6\u4e0a\u53d6\u51b3\u4e8e\u60a8\u3002\u60a8\u53ef\u80fd\u5e0c\u671b\u5c06\u6b64\u4fe1\u606f\u8bb0\u5f55\u5230\u62a5\u544a\u6587\u4ef6\u3001\u5c06\u6570\u636e\u5199\u5165\u4e8b\u4ef6\u65e5\u5fd7\u3001\u5411\u7cfb\u7edf\u7ba1\u7406\u5458\u53d1\u9001\u7535\u5b50\u90ae\u4ef6\u6216\u5411\u6700\u7ec8\u7528\u6237\u663e\u793a\u95ee\u9898\u3002\u5728\u8fd9\u91cc\uff0c\u60a8\u53ea\u9700\u5c06\u5185\u5bb9\u8f6c\u50a8\u5230\u63a7\u5236\u53f0\u7a97\u53e3\uff1a<\/p>\n<p>\/\/ Speed up past the car's max speed to<br \/>\n\/\/ trigger the exception.<br \/>\ntry<\/p>\n<p>{<br \/>\nfor(int i = 0; i &lt; 10; i++)<br \/>\n{<br \/>\nmyCar. Accelerate(10);<br \/>\n}<br \/>\n}<br \/>\ncatch(Exception e)<br \/>\n{<br \/>\n\/\/ Handle the thrown exception. Console.WriteLine(&quot;\\n<strong><em> Error! <\/em><\/strong>&quot;); Console.WriteLine(&quot;Method: {0}&quot;, e.TargetSite);<br \/>\nConsole.WriteLine(&quot;Message: {0}&quot;, e.Message);<br \/>\nConsole.WriteLine(&quot;Source: {0}&quot;, e.Source);<br \/>\n}<br \/>\n\/\/ The error has been handled, processing continues with the next statement. Console.WriteLine(&quot;\\n<strong><strong><em> Out of exception logic <\/em><\/strong><\/strong>&quot;); Console.ReadLine();<\/p>\n<p>In essence, a try block is a section of statements that may throw an exception during execution. If an exception is detected, the flow of program execution is sent to the appropriate catch block. On the other hand, if the code within a try block does not trigger an exception, the catch block is skipped entirely, and all is right with the world. The following output shows a test run of this program:<br \/>\n\u672c\u8d28\u4e0a\uff0ctry \u5757\u662f\u5728\u6267\u884c\u8fc7\u7a0b\u4e2d\u53ef\u80fd\u5f15\u53d1\u5f02\u5e38\u7684\u8bed\u53e5\u90e8\u5206\u3002\u5982\u679c\u68c0\u6d4b\u5230\u5f02\u5e38\uff0c\u7a0b\u5e8f\u6267\u884c\u6d41\u5c06\u53d1\u9001\u5230\u76f8\u5e94\u7684 catch \u5757\u3002\u53e6\u4e00\u65b9\u9762\uff0c\u5982\u679c try \u5757\u4e2d\u7684\u4ee3\u7801\u6ca1\u6709\u89e6\u53d1\u5f02\u5e38\uff0c\u5219\u5b8c\u5168\u8df3\u8fc7 catch \u5757\uff0c\u4e16\u754c\u4e00\u5207\u6b63\u5e38\u3002\u4ee5\u4e0b\u8f93\u51fa\u663e\u793a\u4e86\u6b64\u7a0b\u5e8f\u7684\u6d4b\u8bd5\u8fd0\u884c\uff1a<\/p>\n<p><strong><strong><em> Simple Exception Example <\/em><\/strong><\/strong><br \/>\n=&gt; Creating a car and stepping on it! Jamming...<br \/>\n=&gt; CurrentSpeed = 30<br \/>\n=&gt; CurrentSpeed = 40<br \/>\n=&gt; CurrentSpeed = 50<br \/>\n=&gt; CurrentSpeed = 60<br \/>\n=&gt; CurrentSpeed = 70<br \/>\n=&gt; CurrentSpeed = 80<br \/>\n=&gt; CurrentSpeed = 90<br \/>\n=&gt; CurrentSpeed = 100<\/p>\n<p><strong><em> Error! <\/em><\/strong><br \/>\nMethod: Void Accelerate(Int32) Message: Zippy has overheated! Source: SimpleException<\/p>\n<p><strong><strong><em> Out of exception logic <\/em><\/strong><\/strong><\/p>\n<p>As you can see, after an exception has been handled, the application is free to continue from the point after the catch block. In some circumstances, a given exception could be critical enough to warrant the termination of the application. However, in a good number of cases, the logic within the exception handler will ensure the application can continue on its merry way (although it could be slightly less functional, such as not being able to connect to a remote data source).<br \/>\n\u5982\u60a8\u6240\u89c1\uff0c\u5728\u5904\u7406\u5f02\u5e38\u540e\uff0c\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u4ece catch \u5757\u4e4b\u540e\u7684\u70b9\u7ee7\u7eed\u3002\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u7ed9\u5b9a\u7684\u4f8b\u5916\u53ef\u80fd\u8db3\u591f\u4e25\u91cd\uff0c\u8db3\u4ee5\u4fdd\u8bc1\u7ec8\u6b62\u7533\u8bf7\u3002\u4f46\u662f\uff0c\u5728\u5f88\u591a\u60c5\u51b5\u4e0b\uff0c\u5f02\u5e38\u5904\u7406\u7a0b\u5e8f\u4e2d\u7684\u903b\u8f91\u5c06\u786e\u4fdd\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u7ee7\u7eed\u5176\u5feb\u4e50\u7684\u65b9\u5f0f\uff08\u5c3d\u7ba1\u5b83\u7684\u529f\u80fd\u53ef\u80fd\u7565\u4f4e\uff0c\u4f8b\u5982\u65e0\u6cd5\u8fde\u63a5\u5230\u8fdc\u7a0b\u6570\u636e\u6e90\uff09\u3002<\/p>\n<h2>Throw As Expression (New 7.0)<\/h2>\n<p>\u6295\u63b7\u4e3a\u8868\u8fbe\u5f0f\uff08\u65b0 7.0\uff09<\/p>\n<p>Prior to C# 7, throw() was a statement, which meant you could throw an exception only where statements are allowed. With C# 7.0 and later, throw() is available as an expression as well and can be called anywhere expressions are allowed.<br \/>\n\u5728 C# 7 \u4e4b\u524d\uff0cthrow\uff08\uff09 \u662f\u4e00\u4e2a\u8bed\u53e5\uff0c\u8fd9\u610f\u5473\u7740\u53ea\u6709\u5728\u5141\u8bb8\u8bed\u53e5\u7684\u60c5\u51b5\u4e0b\u624d\u80fd\u5f15\u53d1\u5f02\u5e38\u3002\u5728 C# 7.0 \u53ca\u66f4\u9ad8\u7248\u672c\u4e2d\uff0cthrow\uff08\uff09 \u4e5f\u53ef\u4ee5\u4f5c\u4e3a\u8868\u8fbe\u5f0f\u4f7f\u7528\uff0c\u5e76\u4e14\u53ef\u4ee5\u5728\u4efb\u4f55\u5141\u8bb8\u8868\u8fbe\u5f0f\u7684\u5730\u65b9\u8c03\u7528\u3002<\/p>\n<h2>Configuring the State of an Exception<\/h2>\n<p>\u914d\u7f6e\u5f02\u5e38\u7684\u72b6\u6001<\/p>\n<p>Currently, the System.Exception object configured within the Accelerate() method simply establishes a value exposed to the Message property (via a constructor parameter). As shown previously in Table 7-1, however, the Exception class also supplies a number of additional members (TargetSite, StackTrace, HelpLink, and Data) that can be useful in further qualifying the nature of the problem. To spruce up the current example, let\u2019s examine further details of these members on a case-by-case basis.<br \/>\n\u76ee\u524d\uff0c\u5728 Accelerate\uff08\uff09 \u65b9\u6cd5\u4e2d\u914d\u7f6e\u7684 System.Exception \u5bf9\u8c61\u53ea\u662f\u5efa\u7acb\u5411 Message \u5c5e\u6027\u516c\u5f00\u7684\u503c\uff08\u901a\u8fc7\u6784\u9020\u51fd\u6570\u53c2\u6570\uff09\u3002\u4f46\u662f\uff0c\u5982\u524d\u9762\u7684\u8868 7-1 \u6240\u793a\uff0cException \u7c7b\u8fd8\u63d0\u4f9b\u4e86\u8bb8\u591a\u5176\u4ed6\u6210\u5458\uff08TargetSite\u3001StackTrace\u3001HelpLink \u548c Data\uff09\uff0c\u8fd9\u4e9b\u6210\u5458\u53ef\u7528\u4e8e\u8fdb\u4e00\u6b65\u9650\u5b9a\u95ee\u9898\u7684\u6027\u8d28\u3002\u4e3a\u4e86\u7f8e\u5316\u5f53\u524d\u793a\u4f8b\uff0c\u8ba9\u6211\u4eec\u9010\u4e2a\u68c0\u67e5\u8fd9\u4e9b\u6210\u5458\u7684\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<h2>The TargetSite Property<\/h2>\n<p>\u76ee\u6807\u7ad9\u70b9\u5c5e\u6027<\/p>\n<p>The System.Exception.TargetSite property allows you to determine various details about the method that threw a given exception. As shown in the previous code example, printing the value of TargetSite will display the return type, name, and parameter types of the method that threw the exception. However, TargetSite does not return just a vanilla-flavored string but rather a strongly typed System.Reflection. MethodBase object. This type can be used to gather numerous details regarding the offending method, as well as the class that defines the offending method. To illustrate, assume the previous catch logic has been updated as follows:<br \/>\n\u5c5e\u6027\u5141\u8bb8\u60a8\u786e\u5b9a\u6709\u5173\u5f15\u53d1\u7ed9\u5b9a\u5f02\u5e38\u7684\u65b9\u6cd5\u7684\u5404\u79cd\u8be6\u7ec6\u4fe1\u606f\u3002\u5982\u524d\u9762\u7684\u4ee3\u7801\u793a\u4f8b\u6240\u793a\uff0c\u6253\u5370 TargetSite \u7684\u503c\u5c06\u663e\u793a\u5f15\u53d1\u5f02\u5e38\u7684\u65b9\u6cd5\u7684\u8fd4\u56de\u7c7b\u578b\u3001\u540d\u79f0\u548c\u53c2\u6570\u7c7b\u578b\u3002\u4f46\u662f\uff0cTargetSite \u4e0d\u4ec5\u8fd4\u56de\u9999\u8349\u5473\u7684\u5b57\u7b26\u4e32\uff0c\u8fd8\u8fd4\u56de\u5f3a\u7c7b\u578b\u7684 System.Reflection\u3002\u65b9\u6cd5\u5e93\u5bf9\u8c61\u3002\u6b64\u7c7b\u578b\u53ef\u7528\u4e8e\u6536\u96c6\u6709\u5173\u8fdd\u89c4\u65b9\u6cd5\u4ee5\u53ca\u5b9a\u4e49\u8fdd\u89c4\u65b9\u6cd5\u7684\u7c7b\u7684\u5927\u91cf\u8be6\u7ec6\u4fe1\u606f\u3002\u4e3a\u4e86\u8bf4\u660e\u8fd9\u4e00\u70b9\uff0c\u5047\u8bbe\u524d\u9762\u7684 catch \u903b\u8f91\u5df2\u66f4\u65b0\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<p>...<br \/>\n\/\/ TargetSite actually returns a MethodBase object. catch(Exception e)<br \/>\n{<br \/>\nConsole.WriteLine(&quot;\\n<strong><em> Error! <\/em><\/strong>&quot;); Console.WriteLine(&quot;Member name: {0}&quot;, e.TargetSite);<br \/>\nConsole.WriteLine(&quot;Class defining member: {0}&quot;, e.TargetSite.DeclaringType); Console.WriteLine(&quot;Member type: {0}&quot;, e.TargetSite.MemberType); Console.WriteLine(&quot;Message: {0}&quot;, e.Message);<br \/>\nConsole.WriteLine(&quot;Source: {0}&quot;, e.Source);<br \/>\n}<br \/>\nConsole.WriteLine(&quot;\\n<strong><strong><em> Out of exception logic <\/em><\/strong><\/strong>&quot;); Console.ReadLine();<\/p>\n<p>This time, you use the MethodBase.DeclaringType property to determine the fully qualified name of the class that threw the error (SimpleException.Car, in this case) as well as the MemberType property of the MethodBase object to identify the type of member (such as a property versus a method) where this exception originated. In this case, the catch logic will display the following:<br \/>\n\u8fd9\u4e00\u6b21\uff0c\u4f7f\u7528 MethodBase.DeclaringType \u5c5e\u6027\u6765\u786e\u5b9a\u5f15\u53d1\u9519\u8bef\u7684\u7c7b\u7684\u5b8c\u5168\u9650\u5b9a\u540d\uff08\u5728\u672c\u4f8b\u4e2d\u4e3a SimpleException.Car\uff09\uff0c\u5e76\u4f7f\u7528 MethodBase \u5bf9\u8c61\u7684 MemberType \u5c5e\u6027\u6765\u6807\u8bc6\u4ea7\u751f\u6b64\u5f02\u5e38\u7684\u6210\u5458\u7c7b\u578b\uff08\u5982\u5c5e\u6027\u4e0e\u65b9\u6cd5\uff09\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0ccatch \u903b\u8f91\u5c06\u663e\u793a\u4ee5\u4e0b\u5185\u5bb9\uff1a<\/p>\n<p><strong><em> Error! <\/em><\/strong><br \/>\nMember name: Void Accelerate(Int32)<br \/>\nClass defining member: SimpleException.Car Member type: Method<br \/>\nMessage: Zippy has overheated! Source: SimpleException<\/p>\n<h2>The StackTrace Property<\/h2>\n<p>\u5806\u6808\u8ddf\u8e2a\u5c5e\u6027<\/p>\n<p>The System.Exception.StackTrace property allows you to identify the series of calls that resulted in the exception. Be aware that you never set the value of StackTrace, as it is established automatically at the time the exception is created. To illustrate, assume you have once again updated your catch logic.<br \/>\n\u5c5e\u6027\u5141\u8bb8\u60a8\u6807\u8bc6\u5bfc\u81f4\u5f02\u5e38\u7684\u4e00\u7cfb\u5217\u8c03\u7528\u3002\u8bf7\u6ce8\u610f\uff0c\u60a8\u6c38\u8fdc\u4e0d\u4f1a\u8bbe\u7f6e StackTrace \u7684\u503c\uff0c\u56e0\u4e3a\u5b83\u662f\u5728\u521b\u5efa\u5f02\u5e38\u65f6\u81ea\u52a8\u5efa\u7acb\u7684\u3002\u4e3a\u4e86\u8bf4\u660e\u8fd9\u4e00\u70b9\uff0c\u5047\u8bbe\u60a8\u518d\u6b21\u66f4\u65b0\u4e86\u6355\u83b7\u903b\u8f91\u3002<\/p>\n<p>catch(Exception e)<br \/>\n{<br \/>\n...<br \/>\nConsole.WriteLine(&quot;Stack: {0}&quot;, e.StackTrace);<br \/>\n}<\/p>\n<p>If you were to run the program, you would find the following stack trace is printed to the console (your line numbers and file paths may differ, of course):<br \/>\n\u5982\u679c\u8981\u8fd0\u884c\u8be5\u7a0b\u5e8f\uff0c\u60a8\u4f1a\u53d1\u73b0\u4ee5\u4e0b\u5806\u6808\u8ddf\u8e2a\u5df2\u6253\u5370\u5230\u63a7\u5236\u53f0\uff08\u5f53\u7136\uff0c\u60a8\u7684\u884c\u53f7\u548c\u6587\u4ef6\u8def\u5f84\u53ef\u80fd\u4f1a\u6709\u6240\u4e0d\u540c\uff09\uff1a<\/p>\n<p>Stack: at SimpleException.Car.Accelerate(Int32 delta)<br \/>\nin [path to file]\\car.cs:line 57 at <Program>$.<Main>$(String[] args) in [path to file]\\Program.cs:line 20<\/p>\n<p>The string returned from StackTrace documents the sequence of calls that resulted in the throwing of this exception. Notice how the bottommost line number of this string identifies the first call in the<br \/>\nsequence, while the topmost line number identifies the exact location of the offending member. Clearly, this information can be quite helpful during the debugging or logging of a given application, as you are able to \u201cfollow the flow\u201d of the error\u2019s origin.<br \/>\n\u4ece StackTrace \u8fd4\u56de\u7684\u5b57\u7b26\u4e32\u8bb0\u5f55\u4e86\u5bfc\u81f4\u5f15\u53d1\u6b64\u5f02\u5e38\u7684\u8c03\u7528\u5e8f\u5217\u3002\u8bf7\u6ce8\u610f\u6b64\u5b57\u7b26\u4e32\u6700\u5e95\u90e8\u7684\u884c\u53f7\u5982\u4f55\u6807\u8bc6\u5e8f\u5217\uff0c\u800c\u6700\u4e0a\u9762\u7684\u884c\u53f7\u6807\u8bc6\u8fdd\u89c4\u6210\u5458\u7684\u786e\u5207\u4f4d\u7f6e\u3002\u663e\u7136\uff0c\u5728\u8c03\u8bd5\u6216\u8bb0\u5f55\u7ed9\u5b9a\u5e94\u7528\u7a0b\u5e8f\u671f\u95f4\uff0c\u6b64\u4fe1\u606f\u975e\u5e38\u6709\u7528\uff0c\u56e0\u4e3a\u60a8\u53ef\u4ee5\u201c\u8ddf\u8e2a\u9519\u8bef\u6765\u6e90\u7684\u6d41\u7a0b\u201d\u3002<\/p>\n<h2>The HelpLink Property<\/h2>\n<p>\u5e2e\u52a9\u94fe\u63a5\u5c5e\u6027<\/p>\n<p>While the TargetSite and StackTrace properties allow programmers to gain an understanding of a given exception, this information is of little use to the end user. As you have already seen, the System.Exception. Message property can be used to obtain human-readable information that can be displayed to the current user. In addition, the HelpLink property can be set to point the user to a specific URL or standard help file that contains more detailed information.<br \/>\n\u867d\u7136 TargetSite \u548c StackTrace \u5c5e\u6027\u5141\u8bb8\u7a0b\u5e8f\u5458\u4e86\u89e3\u7ed9\u5b9a\u7684\u5f02\u5e38\uff0c\u4f46\u6b64\u4fe1\u606f\u5bf9\u6700\u7ec8\u7528\u6237\u51e0\u4e4e\u6ca1\u6709\u7528\u5904\u3002\u6b63\u5982\u60a8\u5df2\u7ecf\u770b\u5230\u7684\uff0cSystem.Exception\u3002\u6d88\u606f\u5c5e\u6027\u53ef\u7528\u4e8e\u83b7\u53d6\u53ef\u663e\u793a\u7ed9\u5f53\u524d\u7528\u6237\u7684\u4eba\u7c7b\u53ef\u8bfb\u4fe1\u606f\u3002\u6b64\u5916\uff0c\u8fd8\u53ef\u4ee5\u5c06 HelpLink \u5c5e\u6027\u8bbe\u7f6e\u4e3a\u5c06\u7528\u6237\u6307\u5411\u5305\u542b\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u7684\u7279\u5b9a URL \u6216\u6807\u51c6\u5e2e\u52a9\u6587\u4ef6\u3002<\/p>\n<p>By default, the value managed by the HelpLink property is an empty string. Update the exception using object initialization to provide a more interesting value. Here are the relevant updates to the Car. Accelerate() method:<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u7531\u5e2e\u52a9\u94fe\u63a5\u5c5e\u6027\u7ba1\u7406\u7684\u503c\u4e3a\u7a7a\u5b57\u7b26\u4e32\u3002\u4f7f\u7528\u5bf9\u8c61\u521d\u59cb\u5316\u66f4\u65b0\u5f02\u5e38\u4ee5\u63d0\u4f9b\u66f4\u6709\u8da3\u7684\u503c\u3002\u4ee5\u4e0b\u662f\u6c7d\u8f66\u7684\u76f8\u5173\u66f4\u65b0\u3002\u52a0\u901f\uff08\uff09 \u65b9\u6cd5\uff1a<\/p>\n<p>public void Accelerate(int delta)<br \/>\n{<br \/>\nif (_carIsDead)<br \/>\n{<br \/>\nConsole.WriteLine(&quot;{0} is out of order...&quot;, PetName);<br \/>\n}<br \/>\nelse<br \/>\n{<br \/>\nCurrentSpeed += delta;<br \/>\nif (CurrentSpeed &gt;= MaxSpeed)<br \/>\n{<br \/>\nCurrentSpeed = 0;<br \/>\n_carIsDead = true;<\/p>\n<p>\/\/ Use the &quot;throw&quot; keyword to raise an exception and<br \/>\n\/\/ return to the caller.<br \/>\nthrow new Exception($&quot;{PetName} has overheated!&quot;)<br \/>\n{<br \/>\nHelpLink = &quot;<a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\">http:\/\/www.CarsRUs.com<\/a><\/a><\/a>&quot;<br \/>\n};<br \/>\n}<br \/>\nConsole.WriteLine(&quot;=&gt; CurrentSpeed = {0}&quot;, CurrentSpeed);<br \/>\n}<br \/>\n}<\/p>\n<p>The catch logic could now be updated to print this help-link information as follows:<\/p>\n<p>catch(Exception e)<br \/>\n{<br \/>\n...<br \/>\nConsole.WriteLine(&quot;Help Link: {0}&quot;, e.HelpLink);<br \/>\n}<\/p>\n<h2>The Data Property<\/h2>\n<p>\u6570\u636e\u5c5e\u6027<\/p>\n<p>The Data property of System.Exception allows you to fill an exception object with relevant auxiliary information (such as a timestamp). The Data property returns an object implementing an interface named IDictionary, defined in the System.Collections namespace. Chapter 8 examines the role of interface- based programming, as well as the System.Collections namespace. For the time being, just understand that dictionary collections allow you to create a set of values that are retrieved using a specific key. Observe the next update to the Car.Accelerate() method:<br \/>\nSystem.Exception \u7684 Data \u5c5e\u6027\u5141\u8bb8\u60a8\u4f7f\u7528\u76f8\u5173\u7684\u8f85\u52a9\u4fe1\u606f\uff08\u5982\u65f6\u95f4\u6233\uff09\u586b\u5145\u5f02\u5e38\u5bf9\u8c61\u3002Data \u5c5e\u6027\u8fd4\u56de\u4e00\u4e2a\u5bf9\u8c61\uff0c\u8be5\u5bf9\u8c61\u5b9e\u73b0\u5728 System.Collections \u547d\u540d\u7a7a\u95f4\u4e2d\u5b9a\u4e49\u7684\u540d\u4e3a IDictionary \u7684\u63a5\u53e3\u3002\u7b2c8\u7ae0\u63a2\u8ba8\u4e86\u57fa\u4e8e\u63a5\u53e3\u7684\u7f16\u7a0b\u4ee5\u53caSystem.Collections\u547d\u540d\u7a7a\u95f4\u7684\u4f5c\u7528\u3002\u76ee\u524d\uff0c\u53ea\u9700\u4e86\u89e3\u5b57\u5178\u96c6\u5408\u5141\u8bb8\u60a8\u521b\u5efa\u4e00\u7ec4\u4f7f\u7528\u7279\u5b9a\u952e\u68c0\u7d22\u7684\u503c\u3002\u89c2\u5bdf Car.Accelerate\uff08\uff09 \u65b9\u6cd5\u7684\u4e0b\u4e00\u6b21\u66f4\u65b0\uff1a<\/p>\n<p>public void Accelerate(int delta)<br \/>\n{<br \/>\nif (_carIsDead)<br \/>\n{<br \/>\nConsole.WriteLine(&quot;{0} is out of order...&quot;, PetName);<br \/>\n}<br \/>\nelse<br \/>\n{<br \/>\nCurrentSpeed += delta;<br \/>\nif (CurrentSpeed &gt;= MaxSpeed)<br \/>\n{<br \/>\nConsole.WriteLine(&quot;{0} has overheated!&quot;, PetName); CurrentSpeed = 0;<br \/>\n_carIsDead = true;<br \/>\n\/\/ Use the &quot;throw&quot; keyword to raise an exception<br \/>\n\/\/ and return to the caller.<br \/>\nthrow new Exception($&quot;{PetName} has overheated!&quot;)<br \/>\n{<br \/>\nHelpLink = &quot;<a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\">http:\/\/www.CarsRUs.com<\/a><\/a><\/a>&quot;, Data = {<br \/>\n{&quot;TimeStamp&quot;,$&quot;The car exploded at {DateTime.Now}&quot;},<br \/>\n{&quot;Cause&quot;,&quot;You have a lead foot.&quot;}<br \/>\n}<\/p>\n<p>};<br \/>\n}<br \/>\nConsole.WriteLine(&quot;=&gt; CurrentSpeed = {0}&quot;, CurrentSpeed);<br \/>\n}<br \/>\n}<\/p>\n<p>To successfully enumerate over the key-value pairs, make sure you added a using directive for the System.Collections namespace since you will use a DictionaryEntry type in the file containing the class implementing your top-level statements.<br \/>\n\u82e5\u8981\u6210\u529f\u679a\u4e3e\u952e\u503c\u5bf9\uff0c\u8bf7\u786e\u4fdd\u4e3a System.Collections \u547d\u540d\u7a7a\u95f4\u6dfb\u52a0\u4e86 using \u6307\u4ee4\uff0c\u56e0\u4e3a\u60a8\u5c06\u5728\u5305\u542b\u5b9e\u73b0\u9876\u7ea7\u8bed\u53e5\u7684\u7c7b\u7684\u6587\u4ef6\u4e2d\u4f7f\u7528 DictionaryEntry \u7c7b\u578b\u3002<\/p>\n<p>using System.Collections;<\/p>\n<p>Next, you need to update the catch logic to test that the value returned from the Data property is not null (the default value). After that, you use the Key and Value properties of the DictionaryEntry type to print the custom data to the console.<br \/>\n\u63a5\u4e0b\u6765\uff0c\u9700\u8981\u66f4\u65b0 catch \u903b\u8f91\u4ee5\u6d4b\u8bd5\u4ece Data \u5c5e\u6027\u8fd4\u56de\u7684\u503c\u662f\u5426\u4e0d\u4e3a null\uff08\u9ed8\u8ba4\u503c\uff09\u3002\u4e4b\u540e\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 DictionaryEntry \u7c7b\u578b\u7684\u952e\u548c\u503c\u5c5e\u6027\u5c06\u81ea\u5b9a\u4e49\u6570\u636e\u6253\u5370\u5230\u63a7\u5236\u53f0\u3002<\/p>\n<p>catch (Exception e)<br \/>\n{<br \/>\n...<br \/>\nConsole.WriteLine(&quot;\\n-&gt; Custom Data:&quot;); foreach (DictionaryEntry de in e.Data)<br \/>\n{<br \/>\nConsole.WriteLine(&quot;-&gt; {0}: {1}&quot;, de.Key, de.Value);<br \/>\n}<br \/>\n}<\/p>\n<p>With this, here\u2019s the final output you\u2019d see:<br \/>\n\u6709\u4e86\u8fd9\u4e2a\uff0c\u8fd9\u662f\u60a8\u5c06\u770b\u5230\u7684\u6700\u7ec8\u8f93\u51fa\uff1a<\/p>\n<p><strong><strong><em> Simple Exception Example <\/em><\/strong><\/strong><br \/>\n=&gt; Creating a car and stepping on it! Jamming...<br \/>\n=&gt; CurrentSpeed = 30<br \/>\n=&gt; CurrentSpeed = 40<br \/>\n=&gt; CurrentSpeed = 50<br \/>\n=&gt; CurrentSpeed = 60<br \/>\n=&gt; CurrentSpeed = 70<br \/>\n=&gt; CurrentSpeed = 80<br \/>\n=&gt; CurrentSpeed = 90<br \/>\n<strong><em> Error! <\/em><\/strong><br \/>\nMember name: Void Accelerate(Int32)<br \/>\nClass defining member: SimpleException.Car Member type: Method<br \/>\nMessage: Zippy has overheated! Source: SimpleException<br \/>\nStack: at SimpleException.Car.Accelerate(Int32 delta) ... at SimpleException.Program.Main(String[] args) ...<br \/>\nHelp Link: <a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\">http:\/\/www.CarsRUs.com<\/a><\/a><\/a><\/p>\n<p>-&gt; Custom Data:<br \/>\n-&gt; TimeStamp: The car exploded at 3\/15\/2020 16:22:59<br \/>\n-&gt; Cause: You have a lead foot.<\/p>\n<p><strong><strong><em> Out of exception logic <\/em><\/strong><\/strong><\/p>\n<p>The Data property is useful in that it allows you to pack in custom information regarding the error at hand, without requiring the building of a new class type to extend the Exception base class. As helpful as the Data property may be, however, it is still common for developers to build strongly typed exception classes, which handle custom data using strongly typed properties.<br \/>\nData \u5c5e\u6027\u975e\u5e38\u6709\u7528\uff0c\u56e0\u4e3a\u5b83\u5141\u8bb8\u60a8\u6253\u5305\u6709\u5173\u5f53\u524d\u9519\u8bef\u7684\u81ea\u5b9a\u4e49\u4fe1\u606f\uff0c\u800c\u65e0\u9700\u751f\u6210\u65b0\u7684\u7c7b\u7c7b\u578b\u6765\u6269\u5c55 Exception \u57fa\u7c7b\u3002\u4f46\u662f\uff0c\u5c3d\u7ba1 Data \u5c5e\u6027\u53ef\u80fd\u5f88\u6709\u5e2e\u52a9\uff0c\u4f46\u5f00\u53d1\u4eba\u5458\u4ecd\u7136\u5f88\u5e38\u89c1\u5730\u751f\u6210\u5f3a\u7c7b\u578b\u5f02\u5e38\u7c7b\uff0c\u8fd9\u4e9b\u5f02\u5e38\u7c7b\u4f7f\u7528\u5f3a\u7c7b\u578b\u5c5e\u6027\u5904\u7406\u81ea\u5b9a\u4e49\u6570\u636e\u3002<\/p>\n<p>This approach allows the caller to catch a specific exception-derived type, rather than having to dig into a data collection to obtain additional details. To understand how to do this, you need to examine the distinction between system-level and application-level exceptions.<br \/>\nData \u5c5e\u6027\u975e\u5e38\u6709\u7528\uff0c\u56e0\u4e3a\u5b83\u5141\u8bb8\u60a8\u6253\u5305\u6709\u5173\u5f53\u524d\u9519\u8bef\u7684\u81ea\u5b9a\u4e49\u4fe1\u606f\uff0c\u800c\u65e0\u9700\u751f\u6210\u65b0\u7684\u7c7b\u7c7b\u578b\u6765\u6269\u5c55 Exception \u57fa\u7c7b\u3002\u4f46\u662f\uff0c\u5c3d\u7ba1 Data \u5c5e\u6027\u53ef\u80fd\u5f88\u6709\u5e2e\u52a9\uff0c\u4f46\u5f00\u53d1\u4eba\u5458\u4ecd\u7136\u5f88\u5e38\u89c1\u5730\u751f\u6210\u5f3a\u7c7b\u578b\u5f02\u5e38\u7c7b\uff0c\u8fd9\u4e9b\u5f02\u5e38\u7c7b\u4f7f\u7528\u5f3a\u7c7b\u578b\u5c5e\u6027\u5904\u7406\u81ea\u5b9a\u4e49\u6570\u636e\u3002<\/p>\n<h2>System-Level Exceptions (System.SystemException)<\/h2>\n<p>\u7cfb\u7edf\u7ea7\u5f02\u5e38\uff08System.SystemException\uff09<\/p>\n<p>The .NET base class libraries define many classes that ultimately derive from System.Exception. For example, the System namespace defines core exception objects such as ArgumentOutOfRangeException, IndexOutOfRangeException, StackOverflowException, and so forth. Other namespaces define exceptions that reflect the behavior of that namespace. For example, System.Drawing.Printing defines printing exceptions, System.IO defines input\/output-based exceptions, System.Data defines database-centric exceptions, and so forth.<br \/>\n.NET \u57fa\u7c7b\u5e93\u5b9a\u4e49\u4e86\u8bb8\u591a\u6700\u7ec8\u6d3e\u751f\u81ea System.Exception \u7684\u7c7b\u3002\u4f8b\u5982\uff0c\u547d\u540d\u7a7a\u95f4\u5b9a\u4e49\u6838\u5fc3\u5f02\u5e38\u5bf9\u8c61\uff0c\u5982 ArgumentOutOfRangeException\u3001IndexOutOfRangeException\u3001StackOverflowException \u7b49\u3002\u5176\u4ed6\u547d\u540d\u7a7a\u95f4\u5b9a\u4e49\u53cd\u6620\u8be5\u547d\u540d\u7a7a\u95f4\u884c\u4e3a\u7684\u5f02\u5e38\u3002\u4f8b\u5982\uff0cSystem.Drawing.Print \u5b9a\u4e49\u6253\u5370\u5f02\u5e38\uff0cSystem.IO \u5b9a\u4e49\u57fa\u4e8e\u8f93\u5165\/\u8f93\u51fa\u7684\u5f02\u5e38\uff0cSystem.Data \u5b9a\u4e49\u4ee5\u6570\u636e\u5e93\u4e3a\u4e2d\u5fc3\u7684\u5f02\u5e38\uff0c\u7b49\u7b49\u3002<\/p>\n<p>Exceptions that are thrown by the .NET platform are (appropriately) called system exceptions. These exceptions are generally regarded as nonrecoverable, fatal errors. System exceptions derive directly from a base class named System.SystemException, which in turn derives from System.Exception (which derives from System.Object).<br \/>\n.NET \u5e73\u53f0\u5f15\u53d1\u7684\u5f02\u5e38\uff08\u9002\u5f53\u5730\uff09\u79f0\u4e3a\u7cfb\u7edf\u5f02\u5e38\u3002\u8fd9\u4e9b\u5f02\u5e38\u901a\u5e38\u88ab\u89c6\u4e3a\u4e0d\u53ef\u6062\u590d\u7684\u81f4\u547d\u9519\u8bef\u3002\u7cfb\u7edf\u5f02\u5e38\u76f4\u63a5\u6d3e\u751f\u81ea\u540d\u4e3a System.SystemException \u7684\u57fa\u7c7b\uff0c\u800c\u57fa\u7c7b\u53c8\u6d3e\u751f\u81ea System.Exception\uff08\u6d3e\u751f\u81ea System.Object\uff09\u3002<\/p>\n<p>public class SystemException : Exception<br \/>\n{<br \/>\n\/\/ Various constructors.<br \/>\n}<\/p>\n<p>Given that the System.SystemException type does not add any functionality beyond a set of custom constructors, you might wonder why SystemException exists in the first place. Simply put, when an exception type derives from System.SystemException, you are able to determine that the .NET runtime is the entity that has thrown the exception, rather than the code base of the executing application. You can verify this quite simply using the is keyword.<br \/>\n\u9274\u4e8e System.SystemException \u7c7b\u578b\u9664\u4e86\u4e00\u7ec4\u81ea\u5b9a\u4e49\u6784\u9020\u51fd\u6570\u4e4b\u5916\u4e0d\u4f1a\u6dfb\u52a0\u4efb\u4f55\u529f\u80fd\uff0c\u60a8\u53ef\u80fd\u60f3\u77e5\u9053\u4e3a\u4ec0\u4e48 SystemException \u9996\u5148\u5b58\u5728\u3002\u7b80\u800c\u8a00\u4e4b\uff0c\u5f53\u5f02\u5e38\u7c7b\u578b\u6d3e\u751f\u81ea System.SystemException \u65f6\uff0c\u60a8\u53ef\u4ee5\u786e\u5b9a .NET \u8fd0\u884c\u65f6\u662f\u5f15\u53d1\u5f02\u5e38\u7684\u5b9e\u4f53\uff0c\u800c\u4e0d\u662f\u6b63\u5728\u6267\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u4ee3\u7801\u5e93\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 is \u5173\u952e\u5b57\u975e\u5e38\u7b80\u5355\u5730\u9a8c\u8bc1\u8fd9\u4e00\u70b9\u3002<\/p>\n<p>\/\/ True! NullReferenceException is-a SystemException. NullReferenceException nullRefEx = new NullReferenceException(); Console.WriteLine(<br \/>\n&quot;NullReferenceException is-a SystemException? : {0}&quot;, nullRefEx is SystemException);<\/p>\n<h2>Application-Level Exceptions (System.ApplicationException)<\/h2>\n<p>\u5e94\u7528\u7a0b\u5e8f\u7ea7\u5f02\u5e38\uff08System.ApplicationException\uff09<\/p>\n<p>Given that all .NET exceptions are class types, you are free to create your own application-specific exceptions. However, because the System.SystemException base class represents exceptions thrown from the runtime, you might naturally assume that you should derive your custom exceptions from the System.Exception type. You could do this, but you could instead derive from the System. ApplicationException class.<br \/>\n\u9274\u4e8e\u6240\u6709 .NET \u5f02\u5e38\u90fd\u662f\u7c7b\u7c7b\u578b\uff0c\u60a8\u53ef\u4ee5\u81ea\u7531\u521b\u5efa\u81ea\u5df1\u7684\u7279\u5b9a\u4e8e\u5e94\u7528\u7a0b\u5e8f\u7684\u5f02\u5e38\u3002\u4f46\u662f\uff0c\u7531\u4e8e System.SystemException \u57fa\u7c7b\u8868\u793a\u4ece\u8fd0\u884c\u65f6\u5f15\u53d1\u7684\u5f02\u5e38\uff0c\u56e0\u6b64\u60a8\u53ef\u80fd\u81ea\u7136\u800c\u7136\u5730\u5047\u5b9a\u5e94\u6d3e\u751f\u81ea\u5b9a\u4e49\u5f02\u5e38\u4ece\u7cfb\u7edf\u5f02\u5e38\u7c7b\u578b\u3002\u60a8\u53ef\u4ee5\u8fd9\u6837\u505a\uff0c\u4f46\u60a8\u53ef\u4ee5\u4ece\u7cfb\u7edf\u6d3e\u751f\u3002\u5e94\u7528\u7a0b\u5e8f\u5f02\u5e38\u7c7b\u3002<\/p>\n<p>public class ApplicationException : Exception<br \/>\n{<br \/>\n\/\/ Various constructors.<br \/>\n}<\/p>\n<p>Like SystemException, ApplicationException does not define any additional members beyond a set of constructors. Functionally, the only purpose of System.ApplicationException is to identify the source of the error. When you handle an exception deriving from System.ApplicationException, you can assume the exception was raised by the code base of the executing application, rather than by the .NET Core base class libraries or .NET runtime engine.<br \/>\n\u4e0e SystemException \u4e00\u6837\uff0cApplicationException \u9664\u4e86\u4e00\u7ec4\u6784\u9020\u51fd\u6570\u4e4b\u5916\uff0c\u4e0d\u4f1a\u5b9a\u4e49\u4efb\u4f55\u5176\u4ed6\u6210\u5458\u3002\u4ece\u529f\u80fd\u4e0a\u8bb2\uff0cSystem.ApplicationException \u7684\u552f\u4e00\u76ee\u7684\u662f\u8bc6\u522b\u9519\u8bef\u7684\u6e90\u3002\u5904\u7406\u4ece System.ApplicationException \u6d3e\u751f\u7684\u5f02\u5e38\u65f6\uff0c\u53ef\u4ee5\u5047\u5b9a\u5f02\u5e38\u662f\u7531\u6267\u884c\u5e94\u7528\u7a0b\u5e8f\u7684\u4ee3\u7801\u5e93\u5f15\u53d1\u7684\uff0c\u800c\u4e0d\u662f\u7531 .NET Core \u57fa\u7c7b\u5e93\u6216 .NET \u8fd0\u884c\u65f6\u5f15\u64ce\u5f15\u53d1\u7684\u3002<\/p>\n<h2>Building Custom Exceptions, Take 1<\/h2>\n<p>\u6784\u5efa\u81ea\u5b9a\u4e49\u5f02\u5e38\uff0c\u91c7\u7528 1<\/p>\n<p>While you can always throw instances of System.Exception to signal a runtime error (as shown in the first example), it is sometimes advantageous to build a strongly typed exception that represents the unique details of your current problem. For example, assume you want to build a custom exception (named CarIsDeadException) to represent the error of speeding up a doomed automobile. The first step is to derive a new class from System.Exception\/System.ApplicationException (by convention, all exception class names end with the Exception suffix).<br \/>\n\u867d\u7136\u60a8\u59cb\u7ec8\u53ef\u4ee5\u629b\u51fa System.Exception \u7684\u5b9e\u4f8b\u6765\u53d1\u51fa\u8fd0\u884c\u65f6\u9519\u8bef\u7684\u4fe1\u53f7\uff08\u5982\u7b2c\u4e00\u4e2a\u793a\u4f8b\u4e2d\u6240\u793a\uff09\uff0c\u4f46\u6709\u65f6\u6784\u5efa\u4e00\u4e2a\u8868\u793a\u5f53\u524d\u95ee\u9898\u7684\u552f\u4e00\u8be6\u7ec6\u4fe1\u606f\u7684\u5f3a\u7c7b\u578b\u5f02\u5e38\u662f\u6709\u5229\u7684\u3002\u4f8b\u5982\uff0c\u5047\u8bbe\u60a8\u8981\u6784\u5efa\u4e00\u4e2a\u81ea\u5b9a\u4e49\u5f02\u5e38\uff08\u540d\u4e3aCarIsDeadException\uff09\u6765\u8868\u793a\u52a0\u901f\u6ce8\u5b9a\u8981\u5931\u8d25\u7684\u6c7d\u8f66\u7684\u9519\u8bef\u3002\u7b2c\u4e00\u6b65\u662f\u4ece System.Exception\/System.ApplicationException \u6d3e\u751f\u4e00\u4e2a\u65b0\u7c7b\uff08\u6309\u7167\u60ef\u4f8b\uff0c\u6240\u6709\u5f02\u5e38\u7c7b\u540d\u90fd\u4ee5 Exception \u540e\u7f00\u7ed3\u5c3e\uff09\u3002<\/p>\n<p>\u25a0 Note as a rule, all custom exception classes should be defined as public classes (recall that the default access modifier of a non-nested type is internal). The reason is that exceptions are often passed outside of assembly boundaries and should therefore be accessible to the calling code base.<br \/>\n\u8bf7\u6ce8\u610f\uff0c\u4f5c\u4e3a\u4e00\u9879\u89c4\u5219\uff0c\u6240\u6709\u81ea\u5b9a\u4e49\u5f02\u5e38\u7c7b\u90fd\u5e94\u5b9a\u4e49\u4e3a\u516c\u5171\u7c7b\uff08\u56de\u60f3\u4e00\u4e0b\uff0c\u975e\u5d4c\u5957\u7c7b\u578b\u7684\u9ed8\u8ba4\u8bbf\u95ee\u4fee\u9970\u7b26\u662f\u5185\u90e8\u7684\uff09\u3002\u539f\u56e0\u662f\u5f02\u5e38\u901a\u5e38\u5728\u7a0b\u5e8f\u96c6\u8fb9\u754c\u4e4b\u5916\u4f20\u9012\uff0c\u56e0\u6b64\u8c03\u7528\u4ee3\u7801\u5e93\u5e94\u8be5\u53ef\u4ee5\u8bbf\u95ee\u3002<\/p>\n<p>Create a new Console Application project named CustomException, copy the previous Car.cs and Radio.cs files into your new project, and change the namespace that defines the Car and Radio types from SimpleException to CustomException. Next, add a new file named CarIsDeadException.cs and add the following class definition:<br \/>\n\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a CustomException \u7684\u65b0\u63a7\u5236\u53f0\u5e94\u7528\u7a0b\u5e8f\u9879\u76ee\uff0c\u5c06\u4ee5\u524d\u7684 Car.cs \u548c Radio.cs \u6587\u4ef6\u590d\u5236\u5230\u65b0\u9879\u76ee\u4e2d\uff0c\u5e76\u5c06\u5b9a\u4e49 Car \u548c Radio \u7c7b\u578b\u7684\u547d\u540d\u7a7a\u95f4\u4ece SimpleException \u66f4\u6539\u4e3a CustomException\u3002\u63a5\u4e0b\u6765\uff0c\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a CarIsDeadException \u7684\u65b0\u6587\u4ef6.cs\u5e76\u6dfb\u52a0\u4ee5\u4e0b\u7c7b\u5b9a\u4e49\uff1a<\/p>\n<p>namespace CustomException;<br \/>\n\/\/ This custom exception describes the details of the car-is-dead condition.<br \/>\n\/\/ (Remember, you can also simply extend Exception.) public class CarIsDeadException : ApplicationException<br \/>\n{<br \/>\n}<\/p>\n<p>As with any class, you are free to include any number of custom members that can be called within the catch block of the calling logic. You are also free to override any virtual members defined by your parent classes. For example, you could implement CarIsDeadException by overriding the virtual Message property.<br \/>\n\u4e0e\u4efb\u4f55\u7c7b\u4e00\u6837\uff0c\u60a8\u53ef\u4ee5\u81ea\u7531\u5730\u5305\u542b\u4efb\u610f\u6570\u91cf\u7684\u81ea\u5b9a\u4e49\u6210\u5458\uff0c\u8fd9\u4e9b\u6210\u5458\u53ef\u4ee5\u5728\u8c03\u7528\u903b\u8f91\u7684 catch \u5757\u4e2d\u8c03\u7528\u3002\u60a8\u8fd8\u53ef\u4ee5\u81ea\u7531\u8986\u76d6\u7236\u7c7b\u5b9a\u4e49\u7684\u4efb\u4f55\u865a\u62df\u6210\u5458\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u91cd\u5199\u865a\u62df\u6d88\u606f\u5c5e\u6027\u6765\u5b9e\u73b0 CarIsDeadException\u3002<\/p>\n<p>As well, rather than populating a data dictionary (via the Data property) when throwing the exception, the constructor allows the sender to pass in a timestamp and reason for the error. Finally, the timestamp data and cause of the error can be obtained using strongly typed properties.<br \/>\n\u540c\u6837\uff0c\u6784\u9020\u51fd\u6570\u5141\u8bb8\u53d1\u9001\u65b9\u4f20\u5165\u65f6\u95f4\u6233\u548c\u9519\u8bef\u539f\u56e0\uff0c\u800c\u4e0d\u662f\u5728\u5f15\u53d1\u5f02\u5e38\u65f6\u586b\u5145\u6570\u636e\u5b57\u5178\uff08\u901a\u8fc7 Data \u5c5e\u6027\uff09\u3002\u6700\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u5f3a\u7c7b\u578b\u5c5e\u6027\u83b7\u53d6\u65f6\u95f4\u6233\u6570\u636e\u548c\u9519\u8bef\u539f\u56e0\u3002<\/p>\n<p>public class CarIsDeadException : ApplicationException<br \/>\n{<br \/>\nprivate string _messageDetails = String.Empty; public DateTime ErrorTimeStamp {get; set;} public string CauseOfError {get; set;}<\/p>\n<p>public CarIsDeadException(){}<br \/>\npublic CarIsDeadException(string message, string cause, DateTime time)<br \/>\n{<br \/>\n_messageDetails = message; CauseOfError = cause; ErrorTimeStamp = time;<br \/>\n}<\/p>\n<p>\/\/ Override the Exception.Message property. public override string Message<br \/>\n=&gt; $&quot;Car Error Message: {_messageDetails}&quot;;<br \/>\n}<\/p>\n<p>Here, the CarIsDeadException class maintains a private field (_messageDetails) that represents data regarding the current exception, which can be set using a custom constructor. Throwing this exception from the Accelerate() method is straightforward. Simply allocate, configure, and throw a CarIsDeadException type rather than a System.Exception.<br \/>\n\u5728\u8fd9\u91cc\uff0cCarIsDeadException \u7c7b\u7ef4\u62a4\u4e00\u4e2a\u79c1\u6709\u5b57\u6bb5 \uff08_messageDetails\uff09\uff0c\u8be5\u5b57\u6bb5\u8868\u793a\u6709\u5173\u5f53\u524d\u5f02\u5e38\u7684\u6570\u636e\uff0c\u53ef\u4ee5\u4f7f\u7528\u81ea\u5b9a\u4e49\u6784\u9020\u51fd\u6570\u8fdb\u884c\u8bbe\u7f6e\u3002\u4ece Accelerate\uff08\uff09 \u65b9\u6cd5\u5f15\u53d1\u6b64\u5f02\u5e38\u975e\u5e38\u7b80\u5355\u3002\u53ea\u9700\u5206\u914d\u3001\u914d\u7f6e\u548c\u629b\u51fa CarIsDeadException \u7c7b\u578b\uff0c\u800c\u4e0d\u662f System.Exception\u3002<\/p>\n<p>\/\/ Throw the custom CarIsDeadException. public void Accelerate(int delta)<br \/>\n{<br \/>\n...<br \/>\nthrow new CarIsDeadException(<br \/>\n$&quot;{PetName} has overheated!&quot;,<br \/>\n&quot;You have a lead foot&quot;, DateTime.Now )<br \/>\n{<br \/>\nHelpLink = &quot;<a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\">http:\/\/www.CarsRUs.com<\/a><\/a><\/a>&quot;,<br \/>\n};<br \/>\n...<br \/>\n}<\/p>\n<p>To catch this incoming exception, your catch scope can now be updated to catch a specific CarIsDeadException type (however, given that CarIsDeadException \u201cis-a\u201d System.Exception, it is still permissible to catch a System.Exception as well).<br \/>\n\u8981\u6355\u83b7\u6b64\u4f20\u5165\u5f02\u5e38\uff0c\u73b0\u5728\u53ef\u4ee5\u66f4\u65b0\u6355\u83b7\u8303\u56f4\u4ee5\u6355\u83b7\u7279\u5b9a\u7684CarIsDeadException\u7c7b\u578b\uff08\u4f46\u662f\uff0c\u9274\u4e8eCarIsDeadException\u201c\u662f-a\u201dSystem.Exception\uff0c\u4ecd\u7136\u5141\u8bb8\u6355\u83b7System.Exception\uff09\u3002<\/p>\n<p>using CustomException;<\/p>\n<p>Console.WriteLine(&quot;<strong><strong><em> Fun with Custom Exceptions <\/em><\/strong><\/strong>\\n&quot;); Car myCar = new Car(&quot;Rusty&quot;, 90);<\/p>\n<p>try<br \/>\n{<br \/>\n\/\/ Trip exception. myCar.Accelerate(50);<br \/>\n}<br \/>\ncatch (CarIsDeadException e)<\/p>\n<p>{<br \/>\nConsole.WriteLine(e.Message); Console.WriteLine(e.ErrorTimeStamp); Console.WriteLine(e.CauseOfError);<br \/>\n}<br \/>\nConsole.ReadLine();<\/p>\n<p>So, now that you understand the basic process of building a custom exception, it\u2019s time to build on that knowledge.<br \/>\n\u56e0\u6b64\uff0c\u73b0\u5728\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86\u6784\u5efa\u81ea\u5b9a\u4e49\u5f02\u5e38\u7684\u57fa\u672c\u8fc7\u7a0b\uff0c\u662f\u65f6\u5019\u57fa\u4e8e\u8fd9\u4e9b\u77e5\u8bc6\u8fdb\u884c\u6784\u5efa\u4e86\u3002<\/p>\n<h3>Building Custom Exceptions, Take 2<\/h3>\n<p>\u6784\u5efa\u81ea\u5b9a\u4e49\u5f02\u5e38\uff0c\u91c7\u7528 2<\/p>\n<p>The current CarIsDeadException type has overridden the virtual System.Exception.Message property to configure a custom error message and has supplied two custom properties to account for additional bits of data. In reality, however, you are not required to override the virtual Message property, as you could simply pass the incoming message to the parent\u2019s constructor as follows:<br \/>\n\u5f53\u524d\u7684 CarIsDeadException \u7c7b\u578b\u5df2\u8986\u76d6\u865a\u62df System.Exception.Message \u5c5e\u6027\u4ee5\u914d\u7f6e\u81ea\u5b9a\u4e49\u9519\u8bef\u6d88\u606f\uff0c\u5e76\u63d0\u4f9b\u4e86\u4e24\u4e2a\u81ea\u5b9a\u4e49\u5c5e\u6027\u6765\u8003\u8651\u5176\u4ed6\u6570\u636e\u4f4d\u3002\u4f46\u662f\uff0c\u5b9e\u9645\u4e0a\uff0c\u60a8\u4e0d\u9700\u8981\u91cd\u5199\u865a\u62df Message \u5c5e\u6027\uff0c\u56e0\u4e3a\u60a8\u53ea\u9700\u5c06\u4f20\u5165\u6d88\u606f\u4f20\u9012\u7ed9\u7236\u7ea7\u7684\u6784\u9020\u51fd\u6570\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<p>public class CarIsDeadException : ApplicationException<br \/>\n{<br \/>\npublic DateTime ErrorTimeStamp { get; set; } public string CauseOfError { get; set; }<\/p>\n<p>public CarIsDeadException() { }<\/p>\n<p>\/\/ Feed message to parent constructor.<br \/>\npublic CarIsDeadException(string message, string cause, DateTime time)<br \/>\n:base(message)<br \/>\n{<br \/>\nCauseOfError = cause;<br \/>\nErrorTimeStamp = time;<br \/>\n}<br \/>\n}<\/p>\n<p>Notice that this time you have not defined a string variable to represent the message and have not overridden the Message property. Rather, you are simply passing the parameter to your base class constructor. With this design, a custom exception class is little more than a uniquely named class deriving from System. ApplicationException (with additional properties if appropriate), devoid of any base class overrides.<br \/>\n\u8bf7\u6ce8\u610f\uff0c\u8fd9\u6b21\u60a8\u6ca1\u6709\u5b9a\u4e49\u4e00\u4e2a\u5b57\u7b26\u4e32\u53d8\u91cf\u6765\u8868\u793a\u6d88\u606f\uff0c\u4e5f\u6ca1\u6709\u91cd\u5199 Message \u5c5e\u6027\u3002\u76f8\u53cd\uff0c\u60a8\u53ea\u9700\u5c06\u53c2\u6570\u4f20\u9012\u7ed9\u57fa\u7c7b\u6784\u9020\u51fd\u6570\u3002\u901a\u8fc7\u8fd9\u79cd\u8bbe\u8ba1\uff0c\u81ea\u5b9a\u4e49\u5f02\u5e38\u7c7b\u53ea\u4e0d\u8fc7\u662f\u4ece System \u6d3e\u751f\u7684\u552f\u4e00\u547d\u540d\u7c7b\u3002ApplicationException\uff08\u5982\u679c\u9002\u7528\uff0c\u5177\u6709\u5176\u4ed6\u5c5e\u6027\uff09\uff0c\u6ca1\u6709\u4efb\u4f55\u57fa\u7c7b\u91cd\u5199\u3002<\/p>\n<p>Don\u2019t be surprised if most (if not all) of your custom exception classes follow this simple pattern. Many times, the role of a custom exception is not necessarily to provide additional functionality beyond what is inherited from the base classes but to supply a strongly named type that clearly identifies the nature of the error so the client can provide different handler logic for different types of exceptions.<br \/>\n\u5982\u679c\u5927\u591a\u6570\uff08\u5982\u679c\u4e0d\u662f\u5168\u90e8\uff09\u81ea\u5b9a\u4e49\u5f02\u5e38\u7c7b\u90fd\u9075\u5faa\u8fd9\u79cd\u7b80\u5355\u7684\u6a21\u5f0f\uff0c\u8bf7\u4e0d\u8981\u611f\u5230\u60ca\u8bb6\u3002\u5f88\u591a\u65f6\u5019\uff0c\u81ea\u5b9a\u4e49\u5f02\u5e38\u7684\u4f5c\u7528\u4e0d\u4e00\u5b9a\u662f\u63d0\u4f9b\u4ece\u57fa\u7c7b\u7ee7\u627f\u7684\u529f\u80fd\u4e4b\u5916\u7684\u5176\u4ed6\u529f\u80fd\uff0c\u800c\u662f\u63d0\u4f9b\u660e\u786e\u6807\u8bc6\u9519\u8bef\u6027\u8d28\u7684\u5f3a\u540d\u79f0\u7c7b\u578b\uff0c\u4ee5\u4fbf\u5ba2\u6237\u7aef\u53ef\u4ee5\u4e3a\u4e0d\u540c\u7c7b\u578b\u7684\u5f02\u5e38\u63d0\u4f9b\u4e0d\u540c\u7684\u5904\u7406\u7a0b\u5e8f\u903b\u8f91\u3002<\/p>\n<h3>Building Custom Exceptions, Take 3<\/h3>\n<p>\u6784\u5efa\u81ea\u5b9a\u4e49\u5f02\u5e38\uff0c\u91c7\u7528 3<\/p>\n<p>If you want to build a truly prim-and-proper custom exception class, you want to make sure your custom exception does the following:<br \/>\n\u5982\u679c\u8981\u751f\u6210\u4e00\u4e2a\u771f\u6b63\u539f\u59cb\u4e14\u6b63\u786e\u7684\u81ea\u5b9a\u4e49\u5f02\u5e38\u7c7b\uff0c\u5219\u9700\u8981\u786e\u4fdd\u81ea\u5b9a\u4e49\u5f02\u5e38\u6267\u884c\u4ee5\u4e0b\u64cd\u4f5c\uff1a<br \/>\n\u2022   Derives from Exception\/ApplicationException<br \/>\n\u6d3e\u751f\u81ea\u5f02\u5e38\/\u5e94\u7528\u7a0b\u5e8f\u5f02\u5e38<br \/>\n\u2022   Defines a default constructor<br \/>\n\u5b9a\u4e49\u9ed8\u8ba4\u6784\u9020\u51fd\u6570<br \/>\n\u2022Defines a constructor that sets the inherited Message property<br \/>\n\u5b9a\u4e49\u8bbe\u7f6e\u7ee7\u627f\u7684 Message \u5c5e\u6027\u7684\u6784\u9020\u51fd\u6570<br \/>\n\u2022Defines a constructor to handle \u201cinner exceptions\u201d<br \/>\n\u5b9a\u4e49\u7528\u4e8e\u5904\u7406\u201c\u5185\u90e8\u5f02\u5e38\u201d\u7684\u6784\u9020\u51fd\u6570<\/p>\n<p>To complete your examination of building custom exceptions, here is the final iteration of CarIsDeadException, which accounts for each of these special constructors (the properties would be as shown in the previous example):<br \/>\n\u4e3a\u4e86\u5b8c\u6210\u5bf9\u751f\u6210\u81ea\u5b9a\u4e49\u5f02\u5e38\u7684\u68c0\u67e5\uff0c\u4e0b\u9762\u662f CarIsDeadException \u7684\u6700\u7ec8\u8fed\u4ee3\uff0c\u5b83\u8003\u8651\u4e86\u8fd9\u4e9b\u7279\u6b8a\u6784\u9020\u51fd\u6570\u4e2d\u7684\u6bcf\u4e00\u4e2a\uff08\u5c5e\u6027\u5982\u524d\u9762\u7684\u793a\u4f8b\u6240\u793a\uff09\uff1a<\/p>\n<p>public class CarIsDeadException : ApplicationException<br \/>\n{<br \/>\nprivate string _messageDetails = String.Empty; public DateTime ErrorTimeStamp {get; set;} public string CauseOfError {get; set;}<\/p>\n<p>public CarIsDeadException(){}<br \/>\npublic CarIsDeadException(string cause, DateTime time) : this(cause,time,string.Empty)<br \/>\n{<br \/>\n}<br \/>\npublic CarIsDeadException(string cause, DateTime time, string message) : this(cause,time,message, null)<br \/>\n{<br \/>\n}<\/p>\n<p>public CarIsDeadException(string cause, DateTime time, string message, System. Exception inner)<br \/>\n: base(message, inner)<br \/>\n{<br \/>\nCauseOfError = cause;<br \/>\nErrorTimeStamp = time;<br \/>\n}<br \/>\n}<\/p>\n<p>With this update to your custom exception, update the Accelerate() method to the following:<br \/>\n\u901a\u8fc7\u5bf9\u81ea\u5b9a\u4e49\u5f02\u5e38\u7684\u6b64\u66f4\u65b0\uff0c\u5c06 Accelerate\uff08\uff09 \u65b9\u6cd5\u66f4\u65b0\u4e3a\u4ee5\u4e0b\u5185\u5bb9\uff1a<\/p>\n<p>throw new CarIsDeadException(&quot;You have a lead foot&quot;, DateTime.Now,$&quot;{PetName} has overheated!&quot;)<br \/>\n{<br \/>\nHelpLink = &quot;<a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\"><a href=\"http:\/\/www.CarsRUs.com\">http:\/\/www.CarsRUs.com<\/a><\/a><\/a>&quot;,<br \/>\n};<\/p>\n<p>Given that building custom exceptions that adhere to .NET Core best practices really differ by only their name, you will be happy to know that Visual Studio provides a code snippet template named Exception that will autogenerate a new exception class that adheres to .NET best practices. To activate it, type exc in the editor and hit the Tab key (in Visual Studio, hit the Tab key twice).<br \/>\n\u9274\u4e8e\u751f\u6210\u9075\u5faa .NET Core \u6700\u4f73\u505a\u6cd5\u7684\u81ea\u5b9a\u4e49\u5f02\u5e38\u5b9e\u9645\u4e0a\u4ec5\u5728\u540d\u79f0\u4e0a\u6709\u6240\u4e0d\u540c\uff0c\u60a8\u4f1a\u5f88\u9ad8\u5174\u77e5\u9053 Visual Studio \u63d0\u4f9b\u4e86\u4e00\u4e2a\u540d\u4e3a Exception \u7684\u4ee3\u7801\u6bb5\u6a21\u677f\uff0c\u8be5\u6a21\u677f\u5c06\u81ea\u52a8\u751f\u6210\u7b26\u5408 .NET \u6700\u4f73\u505a\u6cd5\u7684\u65b0\u5f02\u5e38\u7c7b\u3002\u8981\u6fc0\u6d3b\u5b83\uff0c\u8bf7\u5728\u7f16\u8f91\u5668\u4e2d\u952e\u5165 exc \u5e76\u6309 Tab \u952e\uff08\u5728 Visual Studio \u4e2d\uff0c\u6309 Tab \u952e\u4e24\u6b21\uff09\u3002<\/p>\n<h2>Multiple Exceptions<\/h2>\n<p>\u5904\u7406\u591a\u4e2a\u5f02\u5e38<\/p>\n<p>In its simplest form, a try block has a single catch block. In reality, though, you often run into situations where the statements within a try block could trigger numerous possible exceptions. Create a new<br \/>\nC# Console Application project named ProcessMultipleExceptions; copy the Car.cs, Radio.cs, and CarIsDeadException.cs files from the previous CustomException example into the new project, and update your namespace names accordingly.<br \/>\n\u5728\u6700\u7b80\u5355\u7684\u5f62\u5f0f\u4e2d\uff0ctry \u5757\u53ea\u6709\u4e00\u4e2a catch \u5757\u3002\u4f46\u662f\uff0c\u5728\u73b0\u5b9e\u4e2d\uff0c\u60a8\u7ecf\u5e38\u4f1a\u9047\u5230 try \u5757\u4e2d\u7684\u8bed\u53e5\u53ef\u80fd\u4f1a\u89e6\u53d1\u8bb8\u591a\u53ef\u80fd\u7684\u5f02\u5e38\u7684\u60c5\u51b5\u3002\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u540d\u4e3a ProcessMultipleExceptions \u7684 C# \u63a7\u5236\u53f0\u5e94\u7528\u7a0b\u5e8f\u9879\u76ee;\u5c06 Car.cs\u3001Radio.cs \u548c CarIsDeadException.cs \u6587\u4ef6\u4ece\u4ee5\u524d\u7684 CustomException \u793a\u4f8b\u590d\u5236\u5230\u65b0\u9879\u76ee\u4e2d\uff0c\u5e76\u76f8\u5e94\u5730\u66f4\u65b0\u547d\u540d\u7a7a\u95f4\u540d\u79f0\u3002<\/p>\n<p>Now, update Car\u2019s Accelerate() method to also throw a predefined base class library ArgumentOutOfRangeException if you pass an invalid parameter (which you can assume is any value less than zero). Note the constructor of this exception class takes the name of the offending argument as the first string, followed by a message describing the error.<br \/>\n\u73b0\u5728\uff0c\u66f4\u65b0 Car \u7684 Accelerate\uff08\uff09 \u65b9\u6cd5\uff0c\u4ee5\u4fbf\u5728\u4f20\u9012\u65e0\u6548\u53c2\u6570\uff08\u53ef\u4ee5\u5047\u5b9a\u8be5\u53c2\u6570\u5c0f\u4e8e\u96f6\u7684\u4efb\u4f55\u503c\uff09\u65f6\u4e5f\u629b\u51fa\u9884\u5b9a\u4e49\u7684\u57fa\u7c7b\u5e93 ArgumentOutOfRangeException\u3002\u8bf7\u6ce8\u610f\uff0c\u6b64\u5f02\u5e38\u7c7b\u7684\u6784\u9020\u51fd\u6570\u5c06\u6709\u95ee\u9898\u7684\u53c2\u6570\u7684\u540d\u79f0\u4f5c\u4e3a\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e32\uff0c\u540e\u8ddf\u63cf\u8ff0\u9519\u8bef\u7684\u6d88\u606f\u3002<\/p>\n<p>\/\/ Test for invalid argument before proceeding. public void Accelerate(int delta)<br \/>\n{<br \/>\nif (delta &lt; 0)<br \/>\n{<br \/>\nthrow new ArgumentOutOfRangeException(nameof(delta), &quot;Speed must be greater than zero&quot;);<br \/>\n}<br \/>\n...<br \/>\n}<\/p>\n<p>\u25a0 Note The nameof() operator returns a string representing the name of the object, in this example the variable delta. This is a safer way to refer to C# objects, methods, and variables when the string version is required.<br \/>\n\u6ce8\u610f nameof\uff08\uff09 \u8fd0\u7b97\u7b26\u8fd4\u56de\u4e00\u4e2a\u8868\u793a\u5bf9\u8c61\u540d\u79f0\u7684\u5b57\u7b26\u4e32\uff0c\u5728\u672c\u4f8b\u4e2d\u4e3a\u53d8\u91cf delta\u3002\u5f53\u9700\u8981\u5b57\u7b26\u4e32\u7248\u672c\u65f6\uff0c\u8fd9\u662f\u5f15\u7528 C# \u5bf9\u8c61\u3001\u65b9\u6cd5\u548c\u53d8\u91cf\u7684\u66f4\u5b89\u5168\u65b9\u6cd5\u3002<\/p>\n<p>The catch logic could now specifically respond to each type of exception.<br \/>\ncatch \u903b\u8f91\u73b0\u5728\u53ef\u4ee5\u4e13\u95e8\u54cd\u5e94\u6bcf\u79cd\u7c7b\u578b\u7684\u5f02\u5e38\u3002<\/p>\n<p>using ProcessMultipleExceptions;<\/p>\n<p>Console.WriteLine(&quot;<strong><strong><em> Handling Multiple Exceptions <\/em><\/strong><\/strong>\\n&quot;); Car myCar = new Car(&quot;Rusty&quot;, 90);<br \/>\ntry<br \/>\n{<br \/>\n\/\/ Trip Arg out of range exception. myCar.Accelerate(-10);<br \/>\n}<br \/>\ncatch (CarIsDeadException e)<br \/>\n{<br \/>\nConsole.WriteLine(e.Message);<br \/>\n}<br \/>\ncatch (ArgumentOutOfRangeException e)<br \/>\n{<br \/>\nConsole.WriteLine(e.Message);<br \/>\n}<br \/>\nConsole.ReadLine();<\/p>\n<p>When you are authoring multiple catch blocks, you must be aware that when an exception is thrown, it will be processed by the first appropriate catch. To illustrate exactly what the \u201cfirst appropriate\u201d catch means, assume you retrofitted the previous logic with an additional catch scope that attempts to handle all exceptions beyond CarIsDeadException and ArgumentOutOfRangeException by catching a general System. Exception as follows:<br \/>\n\u521b\u4f5c\u591a\u4e2a catch \u5757\u65f6\uff0c\u5fc5\u987b\u6ce8\u610f\uff0c\u5f53\u5f15\u53d1\u5f02\u5e38\u65f6\uff0c\u5b83\u5c06\u7531\u7b2c\u4e00\u4e2a\u9002\u5f53\u7684 catch \u5904\u7406\u3002\u4e3a\u4e86\u51c6\u786e\u8bf4\u660e\u201c\u7b2c\u4e00\u4e2a\u9002\u5f53\u7684\u201d\u6355\u83b7\u7684\u542b\u4e49\uff0c\u5047\u8bbe\u60a8\u4f7f\u7528\u5c1d\u8bd5\u5904\u7406\u6240\u6709\u6355\u83b7\u7684\u9644\u52a0\u6355\u83b7\u8303\u56f4\u6765\u6539\u9020\u524d\u9762\u7684\u903b\u8f91CarIsDeadException \u548c ArgumentOutOfRangeException \u4e4b\u5916\u7684\u5f02\u5e38\uff0c\u901a\u8fc7\u6355\u83b7\u4e00\u822c\u7cfb\u7edf\u3002\u4f8b\u5916\u60c5\u51b5\u5982\u4e0b\uff1a<\/p>\n<p>\/\/ This code will not compile!<br \/>\nConsole.WriteLine(&quot;<strong><strong><em> Handling Multiple Exceptions <\/em><\/strong><\/strong>\\n&quot;); Car myCar = new Car(&quot;Rusty&quot;, 90);<\/p>\n<p>try<br \/>\n{<br \/>\n\/\/ Trigger an argument out of range exception. myCar.Accelerate(-10);<br \/>\n}<br \/>\ncatch(Exception e)<br \/>\n{<br \/>\n\/\/ Process all other exceptions? Console.WriteLine(e.Message);<br \/>\n}<br \/>\ncatch (CarIsDeadException e)<br \/>\n{<br \/>\nConsole.WriteLine(e.Message);<br \/>\n}<br \/>\ncatch (ArgumentOutOfRangeException e)<br \/>\n{<br \/>\nConsole.WriteLine(e.Message);<br \/>\n}<br \/>\nConsole.ReadLine();<\/p>\n<p>This exception handling logic generates compile-time errors. The problem is that the first catch block can handle anything derived from System.Exception (given the \u201cis-a\u201d relationship), including the CarIsDeadException and ArgumentOutOfRangeException types. Therefore, the final two catch blocks are unreachable!<br \/>\n\u6b64\u5f02\u5e38\u5904\u7406\u903b\u8f91\u751f\u6210\u7f16\u8bd1\u65f6\u9519\u8bef\u3002\u95ee\u9898\u5728\u4e8e\uff0c\u7b2c\u4e00\u4e2a catch \u5757\u53ef\u4ee5\u5904\u7406\u4ece System.Exception \u6d3e\u751f\u7684\u4efb\u4f55\u5185\u5bb9\uff08\u7ed9\u5b9a\u201cis-a\u201d\u5173\u7cfb\uff09\uff0c\u5305\u62ec CarIsDeadException \u548c ArgumentOutOfRangeException \u7c7b\u578b\u3002\u56e0\u6b64\uff0c\u6700\u540e\u4e24\u4e2a\u6355\u83b7\u5757\u662f\u65e0\u6cd5\u8bbf\u95ee\u7684\uff01<\/p>\n<p>The rule of thumb to keep in mind is to make sure your catch blocks are structured such that the first catch is the most specific exception (i.e., the most derived type in an exception-type inheritance chain), leaving the final catch for the most general (i.e., the base class of a given exception inheritance chain, in this case System.Exception).<br \/>\n\u8981\u8bb0\u4f4f\u7684\u7ecf\u9a8c\u6cd5\u5219\u662f\u786e\u4fdd\u4f60\u7684 catch \u5757\u7684\u7ed3\u6784\u4f7f\u5f97\u7b2c\u4e00\u4e2a catch \u662f\u6700\u5177\u4f53\u7684\u5f02\u5e38\uff08\u5373\u5f02\u5e38\u7c7b\u578b\u7ee7\u627f\u94fe\u4e2d\u6d3e\u751f\u6700\u591a\u7684\u7c7b\u578b\uff09\uff0c\u5c06\u6700\u7ec8\u7684 catch \u7559\u7ed9\u6700\u4e00\u822c\u7684\uff08\u5373\uff0c\u7ed9\u5b9a\u5f02\u5e38\u7ee7\u627f\u94fe\u7684\u57fa\u7c7b\uff0c\u5728\u672c\u4f8b\u4e2d\u4e3a System.Exception\uff09\u3002<\/p>\n<p>Thus, if you want to define a catch block that will handle any errors beyond CarIsDeadException and<br \/>\nArgumentOutOfRangeException, you could write the following:<br \/>\n\u56e0\u6b64\uff0c\u5982\u679c\u4f60\u60f3\u5b9a\u4e49\u4e00\u4e2a\u6355\u83b7\u5757\u6765\u5904\u7406CarIsDeadException\u4e4b\u5916\u7684\u4efb\u4f55\u9519\u8bef\uff0c\u5e76\u4e14ArgumentOutOfRangeException\uff0c\u4f60\u53ef\u4ee5\u5199\u4ee5\u4e0b\u5185\u5bb9\uff1a<\/p>\n<p>\/\/ This code compiles just fine.<br \/>\nConsole.WriteLine(&quot;<strong><strong><em> Handling Multiple Exceptions <\/em><\/strong><\/strong>\\n&quot;); Car myCar = new Car(&quot;Rusty&quot;, 90);<br \/>\ntry<br \/>\n{<br \/>\n\/\/ Trigger an argument out of range exception. myCar.Accelerate(-10);<br \/>\n}<br \/>\ncatch (CarIsDeadException e)<br \/>\n{<br \/>\nConsole.WriteLine(e.Message);<br \/>\n}<br \/>\ncatch (ArgumentOutOfRangeException e)<br \/>\n{<br \/>\nConsole.WriteLine(e.Message);<br \/>\n}<\/p>\n<p>\/\/ This will catch any other exception<br \/>\n\/\/ beyond CarIsDeadException or<br \/>\n\/\/ ArgumentOutOfRangeException. catch (Exception e)<br \/>\n{<br \/>\nConsole.WriteLine(e.Message);<br \/>\n}<br \/>\nConsole.ReadLine();<\/p>\n<p>\u25a0 Note Where at all possible, always favor catching specific exception classes, rather than a general System.Exception. Though it might appear to make life simple in the short term (you may think \u201cah! This catches all the other things I don\u2019t care about.\u201d), in the long term you could end up with strange runtime crashes, as a more serious error was not directly dealt with in your code. remember, a final catch block that deals with System.Exception tends to be very general indeed.<br \/>\n\u6ce8\u610f \u5728\u53ef\u80fd\u7684\u60c5\u51b5\u4e0b\uff0c\u59cb\u7ec8\u503e\u5411\u4e8e\u6355\u83b7\u7279\u5b9a\u7684\u5f02\u5e38\u7c7b\uff0c\u800c\u4e0d\u662f\u4e00\u822c\u7684 System.Exception\u3002\u867d\u7136\u5b83\u53ef\u80fd\u5728\u77ed\u671f\u5185\u770b\u8d77\u6765\u4f7f\u751f\u6d3b\u53d8\u5f97\u7b80\u5355\uff08\u4f60\u53ef\u80fd\u4f1a\u60f3\u201c\u554a\uff01\u8fd9\u6293\u4f4f\u4e86\u6211\u4e0d\u5173\u5fc3\u7684\u6240\u6709\u5176\u4ed6\u4e8b\u60c5\u201c\uff09\uff0c\u4ece\u957f\u8fdc\u6765\u770b\uff0c\u4f60\u6700\u7ec8\u53ef\u80fd\u4f1a\u9047\u5230\u5947\u602a\u7684\u8fd0\u884c\u65f6\u5d29\u6e83\uff0c\u56e0\u4e3a\u66f4\u4e25\u91cd\u7684\u9519\u8bef\u6ca1\u6709\u5728\u4f60\u7684\u4ee3\u7801\u4e2d\u76f4\u63a5\u5904\u7406\u3002\u8bf7\u8bb0\u4f4f\uff0c\u5904\u7406System.Exception\u7684\u6700\u540e\u4e00\u4e2a\u6355\u83b7\u5757\u786e\u5b9e\u975e\u5e38\u901a\u7528\u3002<\/p>\n<h2>General catch Statements<\/h2>\n<p>\u4e00\u822c\u6355\u83b7\u58f0\u660e<\/p>\n<p>C# also supports a \u201cgeneral\u201d catch scope that does not explicitly receive the exception object thrown by a given member.<br \/>\nC# \u8fd8\u652f\u6301\u201c\u5e38\u89c4\u201d\u6355\u83b7\u8303\u56f4\uff0c\u8be5\u8303\u56f4\u4e0d\u663e\u5f0f\u63a5\u6536\u7ed9\u5b9a\u6210\u5458\u5f15\u53d1\u7684\u5f02\u5e38\u5bf9\u8c61\u3002<\/p>\n<p>\/\/ A generic catch.<br \/>\nConsole.WriteLine(&quot;<strong><strong><em> Handling Multiple Exceptions <\/em><\/strong><\/strong>\\n&quot;); Car myCar = new Car(&quot;Rusty&quot;, 90);<br \/>\ntry<br \/>\n{<br \/>\nmyCar.Accelerate(90);<br \/>\n}<br \/>\ncatch<br \/>\n{<br \/>\nConsole.WriteLine(&quot;Something bad happened...&quot;);<br \/>\n}<br \/>\nConsole.ReadLine();<\/p>\n<p>Obviously, this is not the most informative way to handle exceptions since you have no way to obtain meaningful data about the error that occurred (such as the method name, call stack, or custom message). Nevertheless, C# does allow for such a construct, which can be helpful when you want to handle all errors in a general fashion.<br \/>\n\u663e\u7136\uff0c\u8fd9\u4e0d\u662f\u5904\u7406\u5f02\u5e38\u7684\u6700\u6709\u7528\u7684\u65b9\u6cd5\uff0c\u56e0\u4e3a\u60a8\u65e0\u6cd5\u83b7\u53d6\u6709\u5173\u6240\u53d1\u751f\u9519\u8bef\u7684\u6709\u610f\u4e49\u7684\u6570\u636e\uff08\u4f8b\u5982\u65b9\u6cd5\u540d\u79f0\u3001\u8c03\u7528\u5806\u6808\u6216\u81ea\u5b9a\u4e49\u6d88\u606f\uff09\u3002\u5c3d\u7ba1\u5982\u6b64\uff0cC# \u786e\u5b9e\u5141\u8bb8\u8fd9\u6837\u7684\u6784\u9020\uff0c\u5f53\u60a8\u5e0c\u671b\u4ee5\u5e38\u89c4\u65b9\u5f0f\u5904\u7406\u6240\u6709\u9519\u8bef\u65f6\uff0c\u8fd9\u4f1a\u5f88\u6709\u5e2e\u52a9\u3002<\/p>\n<h2>Rethrowing Exceptions<\/h2>\n<p>\u91cd\u65b0\u5f15\u53d1\u5f02\u5e38<\/p>\n<p>When you catch an exception, it is permissible for the logic in a try block to rethrow the exception up the call stack to the previous caller. To do so, simply use throw() within a catch block. This passes the exception up the chain of calling logic, which can be helpful if your catch block is only able to partially handle the error at hand.<br \/>\n\u6355\u83b7\u5f02\u5e38\u65f6\uff0c\u5141\u8bb8 try \u5757\u4e2d\u7684\u903b\u8f91\u5c06\u5f02\u5e38\u91cd\u65b0\u629b\u51fa\u5230\u8c03\u7528\u5806\u6808\u4e2d\u5230\u524d\u4e00\u4e2a\u8c03\u7528\u65b9\u3002\u4e3a\u6b64\uff0c\u53ea\u9700\u5728 catch \u5757\u4e2d\u4f7f\u7528 throw\uff08\uff09\u3002 \u8fd9\u4f1a\u5c06\u5f02\u5e38\u4f20\u9012\u5230\u8c03\u7528\u903b\u8f91\u94fe\u4e0a\uff0c\u5982\u679c\u60a8\u7684 catch \u5757\u53ea\u80fd\u90e8\u5206\u5904\u7406\u624b\u5934\u7684\u9519\u8bef\uff0c\u8fd9\u4f1a\u5f88\u6709\u5e2e\u52a9\u3002<\/p>\n<p>\/\/ Passing the buck.<br \/>\n...<br \/>\ntry<br \/>\n{<br \/>\n\/\/ Speed up car logic...<br \/>\n}<br \/>\ncatch(CarIsDeadException e)<br \/>\n{<br \/>\n\/\/ Do any partial processing of this error and pass the buck. throw;<br \/>\n}<br \/>\n...<\/p>\n<p>Be aware that, in this example code, the ultimate receiver of CarIsDeadException is the .NET runtime because it is the top-level statements rethrowing the exception. Because of this, your end user is presented with a system-supplied error dialog box. Typically, you would only rethrow a partial handled exception to a caller that has the ability to handle the incoming exception more gracefully.<br \/>\n\u8bf7\u6ce8\u610f\uff0c\u5728\u6b64\u793a\u4f8b\u4ee3\u7801\u4e2d\uff0cCarIsDeadException \u7684\u6700\u7ec8\u63a5\u6536\u65b9\u662f .NET \u8fd0\u884c\u65f6\uff0c\u56e0\u4e3a\u5b83\u662f\u91cd\u65b0\u5f15\u53d1\u5f02\u5e38\u7684\u9876\u7ea7\u8bed\u53e5\u3002\u56e0\u6b64\uff0c\u6700\u7ec8\u7528\u6237\u4f1a\u770b\u5230\u7cfb\u7edf\u63d0\u4f9b\u7684\u9519\u8bef\u5bf9\u8bdd\u6846\u3002\u901a\u5e38\uff0c\u60a8\u53ea\u4f1a\u5c06\u90e8\u5206\u5904\u7406\u7684\u5f02\u5e38\u91cd\u65b0\u5f15\u53d1\u7ed9\u80fd\u591f\u66f4\u4f18\u96c5\u5730\u5904\u7406\u4f20\u5165\u5f02\u5e38\u7684\u8c03\u7528\u65b9\u3002<\/p>\n<p>Notice as well that you are not explicitly rethrowing the CarIsDeadException object but rather making use of throw() with no argument. You\u2019re not creating a new exception object; you\u2019re just rethrowing<br \/>\nthe original exception object (with all its original information). Doing so preserves the context of the original target.<br \/>\n\u8fd8\u8981\u6ce8\u610f\u7684\u662f\uff0c\u4f60\u6ca1\u6709\u663e\u5f0f\u5730\u91cd\u65b0\u629b\u51fa CarIsDeadException \u5bf9\u8c61\uff0c\u800c\u662f\u5728\u6ca1\u6709\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u4f7f\u7528 throw\uff08\uff09\u3002 \u60a8\u6ca1\u6709\u521b\u5efa\u65b0\u7684\u5f02\u5e38\u5bf9\u8c61;\u4f60\u53ea\u662f\u5728\u91cd\u65b0\u6295\u63b7\u539f\u59cb\u5f02\u5e38\u5bf9\u8c61\uff08\u53ca\u5176\u6240\u6709\u539f\u59cb\u4fe1\u606f\uff09\u3002\u8fd9\u6837\u505a\u53ef\u4ee5\u4fdd\u7559\u539f\u59cb\u76ee\u6807\u7684\u4e0a\u4e0b\u6587\u3002<\/p>\n<h2>Inner Exceptions<\/h2>\n<p>\u5185\u90e8\u5f02\u5e38<\/p>\n<p>As you might suspect, it is entirely possible to trigger an exception at the time you are handling another exception. For example, assume you are handling a CarIsDeadException within a particular catch scope and during the process you attempt to record the stack trace to a file on your C: drive named carErrors. txt (the implicit global using statements grant you access to the System.IO namespace and its I\/O- centric types).<br \/>\n\u6b63\u5982\u60a8\u53ef\u80fd\u6000\u7591\u7684\u90a3\u6837\uff0c\u5b8c\u5168\u6709\u53ef\u80fd\u5728\u5904\u7406\u53e6\u4e00\u4e2a\u5f02\u5e38\u65f6\u89e6\u53d1\u5f02\u5e38\u3002\u4f8b\u5982\uff0c\u5047\u8bbe\u60a8\u6b63\u5728\u7279\u5b9a\u7684 catch \u8303\u56f4\u5185\u5904\u7406 CarIsDeadException\uff0c\u5e76\u4e14\u5728\u6b64\u8fc7\u7a0b\u4e2d\u5c1d\u8bd5\u5c06\u5806\u6808\u8ddf\u8e2a\u8bb0\u5f55\u5230 C\uff1a \u9a71\u52a8\u5668\u4e0a\u540d\u4e3a carErrors \u7684\u6587\u4ef6.txt \uff08\u9690\u5f0f\u5168\u5c40 using \u8bed\u53e5\u6388\u4e88\u60a8\u8bbf\u95ee System.IO \u547d\u540d\u7a7a\u95f4\u53ca\u5176\u4ee5 I\/O \u4e3a\u4e2d\u5fc3\u7684\u7c7b\u578b\uff09\u3002<\/p>\n<p>catch(CarIsDeadException e)<br \/>\n{<br \/>\n\/\/ Attempt to open a file named carErrors.txt on the C drive. FileStream fs = File.Open(@&quot;C:\\carErrors.txt&quot;, FileMode.Open);<br \/>\n...<br \/>\n}<\/p>\n<p>Now, if the specified file is not located on your C: drive, the call to File.Open() results in a FileNotFoundException! Later in this book, you will learn all about the System.IO namespace where you\u2019ll discover how to programmatically determine whether a file exists on the hard drive before attempting to open the file in the first place (thereby avoiding the exception altogether). However, to stay focused on the topic of exceptions, assume the exception has been raised.<br \/>\n\u73b0\u5728\uff0c\u5982\u679c\u6307\u5b9a\u7684\u6587\u4ef6\u4e0d\u5728 C\uff1a \u9a71\u52a8\u5668\u4e0a\uff0c\u5219\u8c03\u7528 File.Open\uff08\uff09 \u4f1a\u5bfc\u81f4 FileNotFoundException\uff01\u5728\u672c\u4e66\u7684\u540e\u9762\u90e8\u5206\uff0c\u60a8\u5c06\u4e86\u89e3\u6709\u5173 System.IO \u547d\u540d\u7a7a\u95f4\u7684\u6240\u6709\u4fe1\u606f\uff0c\u60a8\u5c06\u5728\u5176\u4e2d\u4e86\u89e3\u5982\u4f55\u5728\u5c1d\u8bd5\u6253\u5f00\u6587\u4ef6\u4e4b\u524d\u4ee5\u7f16\u7a0b\u65b9\u5f0f\u786e\u5b9a\u786c\u76d8\u9a71\u52a8\u5668\u4e0a\u662f\u5426\u5b58\u5728\u6587\u4ef6\uff08\u4ece\u800c\u5b8c\u5168\u907f\u514d\u5f02\u5e38\uff09\u3002\u4f46\u662f\uff0c\u4e3a\u4e86\u7ee7\u7eed\u5173\u6ce8\u5f02\u5e38\u4e3b\u9898\uff0c\u8bf7\u5047\u8bbe\u5df2\u5f15\u53d1\u5f02\u5e38\u3002<\/p>\n<p>When you encounter an exception while processing another exception, best practice states that you should record the new exception object as an \u201cinner exception\u201d within a new object of the same type as the initial exception. (That was a mouthful!) The reason you need to allocate a new object of the exception being handled is that the only way to document an inner exception is via a constructor parameter. Consider the following code:<br \/>\n\u73b0\u5728\uff0c\u5982\u679c\u6307\u5b9a\u7684\u6587\u4ef6\u4e0d\u5728 C\uff1a \u9a71\u52a8\u5668\u4e0a\uff0c\u5219\u8c03\u7528 File.Open\uff08\uff09 \u4f1a\u5bfc\u81f4 FileNotFoundException\uff01\u5728\u672c\u4e66\u7684\u540e\u9762\u90e8\u5206\uff0c\u60a8\u5c06\u4e86\u89e3\u6709\u5173 System.IO \u547d\u540d\u7a7a\u95f4\u7684\u6240\u6709\u4fe1\u606f\uff0c\u60a8\u5c06\u5728\u5176\u4e2d\u4e86\u89e3\u5982\u4f55\u5728\u5c1d\u8bd5\u6253\u5f00\u6587\u4ef6\u4e4b\u524d\u4ee5\u7f16\u7a0b\u65b9\u5f0f\u786e\u5b9a\u786c\u76d8\u9a71\u52a8\u5668\u4e0a\u662f\u5426\u5b58\u5728\u6587\u4ef6\uff08\u4ece\u800c\u5b8c\u5168\u907f\u514d\u5f02\u5e38\uff09\u3002\u4f46\u662f\uff0c\u4e3a\u4e86\u7ee7\u7eed\u5173\u6ce8\u5f02\u5e38\u4e3b\u9898\uff0c\u8bf7\u5047\u8bbe\u5df2\u5f15\u53d1\u5f02\u5e38\u3002<\/p>\n<p>\/\/Update the exception handler catch (CarIsDeadException e)<br \/>\n{<\/p>\n<p>try<br \/>\n{<br \/>\nFileStream fs = File.Open(@&quot;C:\\carErrors.txt&quot;, FileMode.Open);<br \/>\n...<br \/>\n}<br \/>\ncatch (Exception e2)<br \/>\n{<br \/>\n\/\/This causes a compile error-InnerException is read only<br \/>\n\/\/e.InnerException = e2;<br \/>\n\/\/ Throw an exception that records the new exception,<br \/>\n\/\/ as well as the message of the first exception.<br \/>\nthrow new CarIsDeadException( e.CauseOfError, e.ErrorTimeStamp, e.Message, e2); }<br \/>\n}<\/p>\n<p>Notice, in this case, I have passed in the FileNotFoundException object as the fourth parameter to the CarIsDeadException constructor. After you have configured this new object, you throw it up the call stack to the next caller, which in this case would be the top-level statements.<br \/>\n\u8bf7\u6ce8\u610f\uff0c\u5728\u672c\u4f8b\u4e2d\uff0c\u6211\u5df2\u7ecf\u5c06FileNotFoundException\u5bf9\u8c61\u4f5c\u4e3a\u7b2c\u56db\u4e2a\u53c2\u6570\u4f20\u9012\u7ed9CarIsDeadException\u6784\u9020\u51fd\u6570\u3002\u914d\u7f6e\u6b64\u65b0\u5bf9\u8c61\u540e\uff0c\u5c06\u5176\u5c06\u8c03\u7528\u5806\u6808\u629b\u51fa\u7ed9\u4e0b\u4e00\u4e2a\u8c03\u7528\u65b9\uff0c\u5728\u672c\u4f8b\u4e2d\u4e3a\u9876\u7ea7\u8bed\u53e5\u3002<\/p>\n<p>Given that there is no \u201cnext caller\u201d after the top-level statements to catch the exception, you would be again presented with an error dialog box. Much like the act of rethrowing an exception, recording inner exceptions is usually useful only when the caller has the ability to gracefully catch the exception in the first place. If this is the case, the caller\u2019s catch logic can use the InnerException property to extract the details of the inner exception object.<br \/>\n\u9274\u4e8e\u9876\u7ea7\u8bed\u53e5\u540e\u6ca1\u6709\u201c\u4e0b\u4e00\u4e2a\u8c03\u7528\u65b9\u201d\u6765\u6355\u83b7\u5f02\u5e38\uff0c\u60a8\u5c06\u518d\u6b21\u770b\u5230\u4e00\u4e2a\u9519\u8bef\u5bf9\u8bdd\u6846\u3002\u4e0e\u91cd\u65b0\u5f15\u53d1\u5f02\u5e38\u7684\u884c\u4e3a\u975e\u5e38\u76f8\u4f3c\uff0c\u8bb0\u5f55\u5185\u90e8\u5f02\u5e38\u901a\u5e38\u4ec5\u5728\u8c03\u7528\u65b9\u80fd\u591f\u9996\u5148\u4f18\u96c5\u5730\u6355\u83b7\u5f02\u5e38\u65f6\u624d\u6709\u7528\u3002\u5982\u679c\u662f\u8fd9\u79cd\u60c5\u51b5\uff0c\u8c03\u7528\u65b9\u7684 catch \u903b\u8f91\u53ef\u4ee5\u4f7f\u7528 InnerException \u5c5e\u6027\u63d0\u53d6\u5185\u90e8\u5f02\u5e38\u5bf9\u8c61\u7684\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<h2>The finally Block<\/h2>\n<p>\u6700\u540e\u7684\u8857\u533a<br \/>\nA try\/catch scope may also define an optional finally block. The purpose of a finally block is to ensure that a set of code statements will always execute, exception (of any type) or not. To illustrate, assume you want to always power down the car\u2019s radio before exiting the program, regardless of any handled exception.<br \/>\ntry\/catch \u8303\u56f4\u4e5f\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a\u53ef\u9009\u7684 finally \u5757\u3002finally \u5757\u7684\u76ee\u7684\u662f\u786e\u4fdd\u4e00\u7ec4\u4ee3\u7801\u8bed\u53e5\u59cb\u7ec8\u6267\u884c\uff0c\u65e0\u8bba\u662f\u5426\u5f02\u5e38\uff08\u4efb\u4f55\u7c7b\u578b\u7684\uff09\u3002\u4e3a\u4e86\u8bf4\u660e\u8fd9\u4e00\u70b9\uff0c\u5047\u8bbe\u60a8\u5e0c\u671b\u59cb\u7ec8\u5728\u9000\u51fa\u7a0b\u5e8f\u4e4b\u524d\u5173\u95ed\u6c7d\u8f66\u7684\u6536\u97f3\u673a\uff0c\u800c\u4e0d\u7ba1\u4efb\u4f55\u5904\u7406\u7684\u5f02\u5e38\u3002<\/p>\n<p>Console.WriteLine(&quot;<strong><strong><em> Handling Multiple Exceptions <\/em><\/strong><\/strong>\\n&quot;); Car myCar = new Car(&quot;Rusty&quot;, 90);<br \/>\nmyCar.CrankTunes(true); try<br \/>\n{<br \/>\n\/\/ Speed up car logic.<br \/>\n}<br \/>\ncatch(CarIsDeadException e)<br \/>\n{<br \/>\n\/\/ Process CarIsDeadException.<br \/>\n}<br \/>\ncatch(ArgumentOutOfRangeException e)<br \/>\n{<br \/>\n\/\/ Process ArgumentOutOfRangeException.<br \/>\n}<br \/>\ncatch(Exception e)<br \/>\n{<br \/>\n\/\/ Process any other Exception.<br \/>\n}<\/p>\n<p>finally<br \/>\n{<br \/>\n\/\/ This will always occur. Exception or not. myCar.CrankTunes(false);<br \/>\n}<br \/>\nConsole.ReadLine();<\/p>\n<p>If you did not include a finally block, the radio would not be turned off if an exception were encountered (which might or might not be problematic). In a more real-world scenario, when you need to dispose of objects, close a file, or detach from a database (or whatever), a finally block ensures a location for proper cleanup.<br \/>\n\u5982\u679c\u672a\u5305\u542b finally \u5757\uff0c\u5219\u5728\u9047\u5230\u5f02\u5e38\u65f6\u4e0d\u4f1a\u5173\u95ed\u65e0\u7ebf\u7535\uff08\u53ef\u80fd\u4f1a\u4e5f\u53ef\u80fd\u6ca1\u6709\u95ee\u9898\uff09\u3002\u5728\u66f4\u771f\u5b9e\u7684\u573a\u666f\u4e2d\uff0c\u5f53\u60a8\u9700\u8981\u91ca\u653e\u5bf9\u8c61\u3001\u5173\u95ed\u6587\u4ef6\u6216\u4ece\u6570\u636e\u5e93\u5206\u79bb\uff08\u6216\u5176\u4ed6\u4efb\u4f55\u5185\u5bb9\uff09\u65f6\uff0cfinally \u5757\u53ef\u786e\u4fdd\u6b63\u786e\u6e05\u7406\u7684\u4f4d\u7f6e\u3002<\/p>\n<h2>Exception Filters<\/h2>\n<p>\u5f02\u5e38\u7b5b\u9009\u5668<\/p>\n<p>C# 6 introduced a new clause that can be placed on a catch scope, via the when keyword. When you add this clause, you have the ability to ensure that the statements within a catch block are executed only if some condition in your code holds true. This expression must evaluate to a Boolean (true or false) and can be obtained by using a simple code statement in the when definition itself or by calling an additional method in your code. In a nutshell, this approach allows you to add \u201cfilters\u201d to your exception logic.<br \/>\nC# 6 \u5f15\u5165\u4e86\u4e00\u4e2a\u65b0\u5b50\u53e5\uff0c\u53ef\u4ee5\u901a\u8fc7 when \u5173\u952e\u5b57\u5c06\u5176\u653e\u7f6e\u5728 catch \u4f5c\u7528\u57df\u4e2d\u3002\u6dfb\u52a0\u6b64\u5b50\u53e5\u65f6\uff0c\u80fd\u591f\u786e\u4fdd\u4ec5\u5f53\u4ee3\u7801\u4e2d\u7684\u67d0\u4e9b\u6761\u4ef6\u6210\u7acb\u65f6\uff0c\u624d\u6267\u884c catch \u5757\u4e2d\u7684\u8bed\u53e5\u3002\u6b64\u8868\u8fbe\u5f0f\u7684\u8ba1\u7b97\u7ed3\u679c\u5fc5\u987b\u4e3a\u5e03\u5c14\u503c\uff08\u771f\u6216\u5047\uff09\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728 when \u5b9a\u4e49\u672c\u8eab\u4e2d\u4f7f\u7528\u7b80\u5355\u7684\u4ee3\u7801\u8bed\u53e5\u6216\u5728\u4ee3\u7801\u4e2d\u8c03\u7528\u5176\u4ed6\u65b9\u6cd5\u6765\u83b7\u53d6\u3002\u7b80\u800c\u8a00\u4e4b\uff0c\u6b64\u65b9\u6cd5\u5141\u8bb8\u60a8\u5411\u5f02\u5e38\u903b\u8f91\u6dfb\u52a0\u201c\u7b5b\u9009\u5668\u201d\u3002<\/p>\n<p>Consider the following modified exception logic. I have added a when clause to the CarIsDeadException handler to ensure the catch block is never executed on a Friday (a contrived example, but who wants their automobile to break down right before the weekend?). Notice that the single Boolean statement in the when clause must be wrapped in parentheses.<br \/>\n\u8bf7\u8003\u8651\u4ee5\u4e0b\u4fee\u6539\u540e\u7684\u5f02\u5e38\u903b\u8f91\u3002\u6211\u5728 CarIsDeadException \u5904\u7406\u7a0b\u5e8f\u4e2d\u6dfb\u52a0\u4e86\u4e00\u4e2a when \u5b50\u53e5\uff0c\u4ee5\u786e\u4fdd catch \u5757\u6c38\u8fdc\u4e0d\u4f1a\u5728\u661f\u671f\u4e94\u6267\u884c\uff08\u4e00\u4e2a\u4eba\u4e3a\u7684\u4f8b\u5b50\uff0c\u4f46\u8c01\u5e0c\u671b\u4ed6\u4eec\u7684\u6c7d\u8f66\u5728\u5468\u672b\u4e4b\u524d\u53d1\u751f\u6545\u969c\uff1f\u8bf7\u6ce8\u610f\uff0cwhen \u5b50\u53e5\u4e2d\u7684\u5355\u4e2a\u5e03\u5c14\u8bed\u53e5\u5fc5\u987b\u62ec\u5728\u62ec\u53f7\u4e2d\u3002<\/p>\n<p>catch (CarIsDeadException e) when (e.ErrorTimeStamp.DayOfWeek != DayOfWeek.Friday)<br \/>\n{<br \/>\n\/\/ This new line will only print if the when clause evaluates to true.<br \/>\n\/\/ \u4ec5\u5f53 when \u5b50\u53e5\u7684\u8ba1\u7b97\u7ed3\u679c\u4e3a true \u65f6\uff0c\u624d\u4f1a\u6253\u5370\u6b64\u65b0\u884c\u3002<br \/>\nConsole.WriteLine(&quot;Catching car is dead!&quot;);<\/p>\n<p>Console.WriteLine(e.Message);<br \/>\n}<\/p>\n<p>While this example is very contrived, a more realistic use for using an exception filter is to catch SystemExceptions. For example, suppose your code is saving data to the database, a general exception is thrown. By examining the message and exception data, you can create specific handlers based on what caused the exception.<br \/>\n\u867d\u7136\u6b64\u793a\u4f8b\u975e\u5e38\u4eba\u4e3a\uff0c\u4f46\u4f7f\u7528\u5f02\u5e38\u7b5b\u9009\u5668\u7684\u66f4\u5b9e\u9645\u7528\u9014\u662f\u6355\u83b7 SystemException\u3002\u4f8b\u5982\uff0c\u5047\u8bbe\u60a8\u7684\u4ee3\u7801\u6b63\u5728\u5c06\u6570\u636e\u4fdd\u5b58\u5230\u6570\u636e\u5e93\uff0c\u5219\u4f1a\u5f15\u53d1\u5e38\u89c4\u5f02\u5e38\u3002\u901a\u8fc7\u68c0\u67e5\u6d88\u606f\u548c\u5f02\u5e38\u6570\u636e\uff0c\u53ef\u4ee5\u6839\u636e\u5bfc\u81f4\u5f02\u5e38\u7684\u539f\u56e0\u521b\u5efa\u7279\u5b9a\u7684\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>\/\/ Debugging Unhandled Exceptions Using Visual Studio<br \/>\n\u4f7f\u7528 Visual Studio \u8c03\u8bd5\u672a\u7ecf\u5904\u7406\u7684\u5f02\u5e38<\/p>\n<p>Visual Studio supplies a number of tools that help you debug unhandled exceptions. Assume you have increased the speed of a Car object beyond the maximum but this time did not bother to wrap your call within a try block.<br \/>\nVisual Studio \u63d0\u4f9b\u4e86\u8bb8\u591a\u5de5\u5177\u6765\u5e2e\u52a9\u4f60\u8c03\u8bd5\u672a\u7ecf\u5904\u7406\u7684\u5f02\u5e38\u3002\u5047\u8bbe\u60a8\u5df2\u5c06 Car \u5bf9\u8c61\u7684\u901f\u5ea6\u63d0\u9ad8\u5230\u8d85\u8fc7\u6700\u5927\u503c\uff0c\u4f46\u8fd9\u6b21\u6ca1\u6709\u8d39\u5fc3\u5c06\u60a8\u7684\u8c03\u7528\u5305\u88c5\u5728 try \u5757\u4e2d\u3002<br \/>\nCar myCar = new Car(&quot;Rusty&quot;, 90); myCar.Accelerate(100);<\/p>\n<p>If you start a debugging session within Visual Studio (using the Debug \u27a4 Start Debugging menu selection), Visual Studio automatically breaks at the time the uncaught exception is thrown. Better yet, you are presented with a window (see Figure 7-1) displaying the value of the Message property.<br \/>\n\u5982\u679c\u5728 Visual Studio \u4e2d\u542f\u52a8\u8c03\u8bd5\u4f1a\u8bdd\uff08\u4f7f\u7528\u201c\u8c03\u8bd5\u201d\u27a4\u201c\u542f\u52a8\u8c03\u8bd5\u201d\u83dc\u5355\u9009\u9879\uff09\uff0c\u5219\u5728\u5f15\u53d1\u672a\u6355\u83b7\u7684\u5f02\u5e38\u65f6\uff0cVisual Studio \u4f1a\u81ea\u52a8\u4e2d\u65ad\u3002\u66f4\u597d\u7684\u662f\uff0c\u60a8\u5c06\u770b\u5230\u4e00\u4e2a\u7a97\u53e3\uff08\u8bf7\u53c2\u9605\u56fe 7-1\uff09\uff0c\u5176\u4e2d\u663e\u793a\u4e86 Message \u5c5e\u6027\u7684\u503c\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/0701.jpg\" alt=\"Alt text\" \/><\/p>\n<p>Figure 7-1. Debugging unhandled custom exceptions with Visual Studio<br \/>\n\u56fe 7-1\u3002 \u4f7f\u7528 Visual Studio \u8c03\u8bd5\u672a\u7ecf\u5904\u7406\u7684\u81ea\u5b9a\u4e49\u5f02\u5e38<\/p>\n<p>\u25a0 Note If you fail to handle an exception thrown by a method in the .neT base class libraries, the Visual studio debugger breaks at the statement that called the offending method.<br \/>\n\u6ce8\u610f \u5982\u679c\u65e0\u6cd5\u5904\u7406 .neT \u57fa\u7c7b\u5e93\u4e2d\u7684\u65b9\u6cd5\u5f15\u53d1\u7684\u5f02\u5e38\uff0cVisual Studio \u8c03\u8bd5\u5668\u5c06\u5728\u8c03\u7528\u8fdd\u89c4\u65b9\u6cd5\u7684\u8bed\u53e5\u5904\u4e2d\u65ad\u3002<\/p>\n<p>If you click the View Detail link, you will find the details regarding the state of the object (see Figure 7-2).<br \/>\n\u5982\u679c\u5355\u51fb\u201c\u67e5\u770b\u8be6\u7ec6\u4fe1\u606f\u201d\u94fe\u63a5\uff0c\u5c06\u627e\u5230\u6709\u5173\u5bf9\u8c61\u72b6\u6001\u7684\u8be6\u7ec6\u4fe1\u606f\uff08\u8bf7\u53c2\u9605\u56fe 7-2\uff09\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/0702.jpg\" alt=\"Alt text\" \/><\/p>\n<p>Figure 7-2. Viewing exception details<br \/>\n\u56fe 7-2\u3002 \u67e5\u770b\u5f02\u5e38\u8be6\u7ec6\u4fe1\u606f<\/p>\n<h2>Summary<\/h2>\n<p>\u603b\u7ed3<\/p>\n<p>In this chapter, you examined the role of structured exception handling. When a method needs to send an error object to the caller, it will allocate, configure, and throw a specific System.Exception-derived type via throw(). The caller is able to handle any possible incoming exceptions using the C# catch keyword and an optional finally scope. Since C# 6.0, the ability to create exception filters using the optional when keyword was added, and C# 7 has expanded the locations from where you can throw exceptions.<br \/>\n\u5728\u672c\u7ae0\u4e2d\uff0c\u60a8\u7814\u7a76\u4e86\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406\u7684\u4f5c\u7528\u3002\u5f53\u65b9\u6cd5\u9700\u8981\u5411\u8c03\u7528\u65b9\u53d1\u9001\u9519\u8bef\u5bf9\u8c61\u65f6\uff0c\u5b83\u5c06\u901a\u8fc7 throw\uff08\uff09 \u5206\u914d\u3001\u914d\u7f6e\u548c\u629b\u51fa\u7279\u5b9a\u7684 System.Exception \u6d3e\u751f\u7c7b\u578b\u3002\u8c03\u7528\u65b9\u80fd\u591f\u4f7f\u7528 C# catch \u5173\u952e\u5b57\u548c\u53ef\u9009\u7684 finally \u4f5c\u7528\u57df\u5904\u7406\u4efb\u4f55\u53ef\u80fd\u7684\u4f20\u5165\u5f02\u5e38\u3002\u81ea C# 6.0 \u8d77\uff0c\u6dfb\u52a0\u4e86\u4f7f\u7528\u53ef\u9009 when \u5173\u952e\u5b57\u521b\u5efa\u5f02\u5e38\u7b5b\u9009\u5668\u7684\u529f\u80fd\uff0c\u5e76\u4e14 C# 7 \u6269\u5c55\u4e86\u53ef\u4ee5\u5f15\u53d1\u5f02\u5e38\u7684\u4f4d\u7f6e\u3002<\/p>\n<p>When you are creating your own custom exceptions, you ultimately create a class type deriving from System.ApplicationException, which denotes an exception thrown from the currently executing<br \/>\napplication. In contrast, error objects deriving from System.SystemException represent critical (and fatal)<br \/>\nerrors thrown by the .NET runtime. Last but not least, this chapter illustrated various tools within Visual Studio that can be used to create custom exceptions (according to .NET best practices) as well as debug exceptions.<br \/>\n\u5728\u521b\u5efa\u81ea\u5df1\u7684\u81ea\u5b9a\u4e49\u5f02\u5e38\u65f6\uff0c\u6700\u7ec8\u4f1a\u521b\u5efa\u4e00\u4e2a\u6d3e\u751f\u81ea System.ApplicationException \u7684\u7c7b\u7c7b\u578b\uff0c\u8be5\u7c7b\u7c7b\u578b\u8868\u793a\u4ece\u5f53\u524d\u6267\u884c\u7684\u5e94\u7528\u3002\u76f8\u53cd\uff0c\u6d3e\u751f\u81ea System.SystemException \u7684\u9519\u8bef\u5bf9\u8c61\u8868\u793a\u4e25\u91cd\uff08\u548c\u4e25\u91cd\uff09.NET \u8fd0\u884c\u65f6\u5f15\u53d1\u7684\u9519\u8bef\u3002\u6700\u540e\u4f46\u5e76\u975e\u6700\u4e0d\u91cd\u8981\u7684\u4e00\u70b9\u662f\uff0c\u672c\u7ae0\u6f14\u793a\u4e86Visual Studio\u4e2d\u7684\u5404\u79cd\u5de5\u5177\uff0c\u8fd9\u4e9b\u5de5\u5177\u53ef\u7528\u4e8e\u521b\u5efa\u81ea\u5b9a\u4e49\u5f02\u5e38\uff08\u6839\u636e.NET\u6700\u4f73\u5b9e\u8df5\uff09\u4ee5\u53ca\u8c03\u8bd5\u5f02\u5e38\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>CHAPTER 7 Understanding Structured Exception Handling \u7b2c7\u7ae0 \u4e86\u89e3\u7ed3\u6784\u5316\u5f02\u5e38\u5904\u7406 In this chapter, you will learn how to handle runtime anomalies in your C# code through the use of structured exception handling. Not only will you examine the C# keywords that allow you to handle such matters (try, catch, throw, finally, when), but you will also come [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[22],"class_list":["post-301","post","type-post","status-publish","format-standard","hentry","category-csharp","tag-pro-csharp10-with-net6"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/301","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=301"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/301\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=301"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=301"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=301"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}