找回密码
 立即注册

QQ登录

只需一步,快速开始

Carl

版主

49

主题

213

帖子

962

积分

版主

Rank: 7Rank: 7Rank: 7

积分
962

活字格认证微信认证勋章

QQ
Carl
版主   /  发表于:2009-12-10 12:27  /   查看:8402  /  回复:0
Post by "winking",2007-03-13, 20:17
-----------------------------------------------------

Once, when I was studying C language, somebody who uses Cpp programming teased me on the exception in C (most time, when excption in C, the runtime tips you that you application is in unexpected error, you need restart application), then I was so surprised, what an intellectualized programming language is! then I study Cpp, and when working, I used C# and .NET (sometime C as well), and may contact with exception frequently, however, I like it until I fix a some bugs caused by excpetion machine.

Ok, I am on the assumption that you have mastered all knowledges about excpetion in .NET (or pure Cpp) when read this article (if not, please refer to MSDN, there duzen of articles detail it) , and in next serval pargraphs I would descript what it's my experence on excpetion.

1. Avoid depended on exception to provider error handler.
    As you know int is internal type of .NET, and it provide a method named Parse, you can parse an integer number string to integer, well you have been emphasized that int.Parse method can caused three exceptions:
         ArgumentNullException, s is a null reference (Nothing in Visual Basic).  
         FormatException, s does not consist solely of an optional negative sign followed by a sequence of digits ranging from 0 to 9.
         OverflowException, s represents a number less than MinValue or greater than MaxValue.
maybe some day your boss ask you implement a feature to parse a serials string data to integer, which the string data is stored in a text file and each line a number string, so you write following code snippet:
  1.          int[] nData = new int[DEFINED_NUMBER_COUNT];
  2.          for( int  i= 0; i< DEFINED_NUMBER_COUNT; i++)
  3.          {
  4.                try {
  5.                        nData[i] = int.Parse(dataReader.ReadLine()); // use stream reader to read a line, and try parse this string.
  6.                }
  7.                catch(ArgumentNullException) {
  8.                        nData[i] = -2; // boss told you define '-2' as the line is null string.
  9.                }
  10.                catch(FormatException) {
  11.                        nData[i] = -1; // boss define '-1' as format error.
  12.                }
  13.                catch(OverflowExcption) {
  14.                        nData[i] = 0; // boss says here is customer required
  15.                }
  16.           }
复制代码
as well, it works well when input text data is all right, until one day tester report a bug which complain the application is very slow (at least use more that one hundred times time) than  when customer write an error data to data file by mistake, then you will be crashed. the original reason is that here the implement depended on the exception to parse data, in normal case, it run fast, but once a excpetion thrown, the slow down quickly. for demo, here is solution for this case:
  1.          int[] nData = new int[DEFINED_NUMBER_COUNT];
  2.          for( int  i= 0; i< DEFINED_NUMBER_COUNT; i++)
  3.          {
  4.                string readData = dataReader.ReadLine();
  5.                if(string.IsNullOrEmpty(readData)) {
  6.                       nData[i] = -2;
  7.                       continue;
  8.                }
  9.                int data = 0;
  10.                if(int.TryParse(readData, out data)) {
  11.                       nData[i] = data;
  12.                       continue;
  13.                }
  14.                // some code to verify whether is overflow or not well format string.
  15.                ...
  16.           }
复制代码
2. Think more when you wanna write a loop which inner somewhere would throw exception.
     From the sample of first tip, you can see use exception in loop can cause perfmance crash down, this is just one reason of this tip. Image you are not use try...catch in loop, and the content code in loop throw exception, then what happened? nobody know it, maybe someone use try...catch when call your provided function, then tester told them application would miss data when data is not in well form.
    So, please look before you leap!
3. When in destructor or Dispose method, take care of throw exception.
     Application use unmanaged resource is frequent, most case we dispose them in destructor or Dispose, please take care the exception here, you know, when GC dispose object, it mark object first, then call internal clean up, may you operation caused exception when GC mark your object but finishing clean up your resource, what happened then? memory leak! this case occursed in component programming more frequent.

Conclusion
    exception is a good way to trace bug, but when release products, please look before you leap. Think it more, we can make it better.

Reply by "WilliamLuo", 2007-03-14, 9:23
-----------------------------------------------------

几个收获:

(1)TryParse方法,第一次听说

(2)干啥都不能偷懒,自己的事情还是要自己做,不要依赖Try-catch。

(3)打扫现场的时候,不敢再出错。

Reply by "Carl", 2007-03-14, 10:12
-----------------------------------------------------


Try-Parse模式是为了避免Exception影响性能的工具。如果一个Method在设计时认为它很多情况下都在处理包含错误的信息,那么根据Try-Parse模式,应该设计两个方法:

public object Do(object param); // 这个方法在参数出错时应该扔Exception

public bool TryDo(object param, out object result); // 这个方法在参数出错时返回 false,方法的处理结果使用out型的参数返回。

常见的例子有Int.TryParse,Uri.TryCreate,Dictionary.TryGetValue等

MSDN的描述:

.NET Framework Developer's Guide  
Exceptions and Performance  

  

Throwing exceptions can negatively impact performance. For code that routinely fails, you can use design patterns to minimize performance issues. This topic describes two design patterns that are useful when exceptions might significantly impact performance.

Do not use error codes because of concerns that exceptions might affect performance negatively.
Use design to mitigate performance issues. Two patterns are described in this topic.

Consider the Tester-Doer pattern for members that may throw exceptions in common scenarios to avoid performance problems related to exceptions.
The Tester-Doer pattern divides a call that might throw exceptions into two parts: a Tester and a Doer. The Tester performs a test for the state that can cause the Doer to throw an exception. The test is inserted just before the code that throws the exception, thereby guarding against the exception.

The following code example shows the Doer half of this pattern. The example contains a method that throws an exception when it is passed a null (Nothing in Visual Basic) value. If this method is called often, it could negatively impact performance.

C#
  1. public class Doer
  2. {
  3.     // Method that can potential throw exceptions often.
  4.     public static void ProcessMessage(string message)
  5.     {
  6.         if (message == null)
  7.         {
  8.             throw new ArgumentNullException("message");
  9.         }
  10.     }
  11.     // Other methods...
  12. }
复制代码
The following code example shows the Tester part of this pattern. The method uses a test to prevent the call to the Doer (ProcessMessage) when the Doer would throw an exception.

C#
  1. public class Tester
  2. {
  3.     public static void TesterDoer(ICollection<string> messages)
  4.     {
  5.         foreach (string message in messages)
  6.         {
  7.             // Test to ensure that the call
  8.             // won't cause the exception.
  9.             if (message != null)
  10.             {
  11.                 Doer.ProcessMessage(message);
  12.             }
  13.         }
  14.     }
  15. }
复制代码
Note that you must address potential race conditions if you use this pattern in a multithreaded application where the test involves a mutable object. A thread can change the state of the mutable object after the test but before the Doer executes. Use thread synchronization techniques to address these issues.

Consider the TryParse pattern for members that may throw exceptions in common scenarios to avoid performance problems related to exceptions.
To implement The TryParse pattern, you provide two different methods for performing an operation that can throw exceptions in common scenarios. The first method, X, does the operation and throws the exception when appropriate. The second method, TryX, does not throw the exception, but instead returns a Boolean value indicating success or failure. Any data returned by a successful call to TryX is returned using an out (ByRef in Visual Basic) parameter. The Parse and TryParse methods are examples of this pattern.

Do provide an exception-throwing member for each member using the TryParse pattern.
It is almost always not correct design to provide only the TryX method because it requires understanding out parameters. Also, the performance impact of exceptions is not an issue for most common scenarios; you should provide methods that are easy to use in most common scenarios.

Portions Copyright 2005 Microsoft Corporation. All rights reserved.

Portions Copyright Addison-Wesley Corporation. All rights reserved.

For more information on design guidelines, see the "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" book by Krzysztof Cwalina and Brad Abrams, published by Addison-Wesley, 2005.

See Also
Other Resources
Design Guidelines for Developing Class Libraries
Design Guidelines for Exceptions



To make a suggestion or report a bug about Help or another feature of this product, go to the feedback site.
--------------------------------------------------------------------------------

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部