ホームページ  >  記事  >  バックエンド開発  >  .NET例外処理についての考察(その1)

.NET例外処理についての考察(その1)

黄舟
黄舟オリジナル
2017-02-06 14:43:141237ブラウズ

プロジェクト開発では、システムとコードの安定性とフォールトトレランスに対応する要件があります。実際の開発プロジェクトのコードとサンプル コードの違いは、コードの動作の安定性、フォールト トレランス、スケーラビリティにあります。

関数を実装するためのコア コードは同じであるため、記述に関して最適化されているだけかもしれませんが、特定の操作を実装するために使用されるクラスに関しては、ほとんどのコードが同じです。時間。 。

実際の開発プロセスでは、特定の機能の実装に限定されず、コードの安定性やスケーラビリティなど、多くの問題を考慮する必要があるようです。

上記は、実際の開発で直面する必要がある問題であり、最近のブログ投稿では、この例外をどのように記述するか、例外をどのように理解するかについても考えています。 garden friends 例外の書き方と扱いについて私なりの意見を述べました。比較的簡単で大雑把かもしれませんが、偉い人たちの話を導くための導入としてのみ使用します。実際のプロジェクトの経験について。この記事が皆様のお役に立てば幸いです。皆様もぜひご自身のアイデアや意見を提出し、知識や洞察を共有してください。

1. DotNET 例外の概要

例外についてすべてを学びたい場合は、一般的な概念を理解できるように、何を学びたいのかを知る必要があります。心。メンバーが、その名前に示されている実行可能なアクションの実行に失敗すると、例外が発生します。

.NET では、コンストラクター、プロパティの取得と設定、イベントの追加と削除、演算子のオーバーロードの呼び出し、変換演算子の呼び出しなどでエラー コードを返す方法はありません。ただし、これらのコンストラクターのエラーを報告する必要がある場合は、例外処理メカニズムを提供する必要があります。

例外処理では、try ブロック、finally ブロックの 3 つのブロックがよく使用されます。これら 3 つのブロックは併用することも、catch ブロックを使用せずにネストして使用することもできます。その具体的な方法を以下に紹介します。

例外処理メカニズムには、通常 3 つのオプションがあります。同じ例外を再スローし、例外が発生したことをコール スタック内の上位レベルのコードに通知し、別の例外を上位レベルのコードに提供します。呼び出しスタックの豊富な例外情報により、スレッドが catch ブロックの最後から抜け出すようになります。

例外を処理する方法については、いくつかの指針となる提案があります。

1.finally ブロックを適切に使用する

final ブロッ​​クは、通常、スレッドがスローした例外の種類に関係なく、正常に開始された操作をクリーンアップするために使用されます。呼び出し元に戻るか、その後最終的にコードをブロックします。

2. 例外のキャッチは適切である必要があります

なぜ例外を適切にキャッチする必要があるのでしょうか?次のコードは、すべての例外をキャッチした後、それらの例外を処理する必要があるため、発生する例外を予測できません。

アプリケーション コードが例外をスローした場合、アプリケーションのもう一方の端はこの例外をキャッチすることを期待している可能性があるため、「サイズがすべてに適合する」例外ブロックとして記述することはできません。例外は呼び出しを上位に移動できるようにする必要があります。プログラムコードはこの例外を特別に処理します。

catch ブロックでは、System.Exception を使用して例外をキャッチできますが、catch ブロックの最後で例外を再スローすることをお勧めします。その理由は後述する。

try{
  var hkml = GetRegistryKey(rootKey);
  var subkey = hkml.CreateSubKey(subKey);
  if (subkey != null && keyName != string.Empty)
  subkey.SetValue(keyName, keyValue, RegistryValueKind.String);
}
catch (Exception ex)
{
         Log4Helper.Error("创建注册表错误" + ex);
         throw new Exception(ex.Message,ex);
}

3. 例外からの回復

例外をキャッチした後、プログラムの実行を継続できるようにするための例外回復コードを記述することができます。例外をキャッチするときは、特定の例外をキャッチし、どのような状況で例外がスローされるかを完全に理解し、キャッチされた例外の型からどの型が派生するかを把握する必要があります。 catch ブロックの最後で再スローされない限り、System.Exception 例外を処理またはキャッチしないでください。

4. 状態を維持する

一般に、操作またはメソッドを完了するときは、実行プロセス中にいくつかのメソッドを組み合わせて呼び出す必要があり、最初のいくつかのメソッドが完了し、後続のメソッドが完了します。異常であること。回復不可能な例外が発生した場合、情報を復元する必要があるため、部分的に完了した操作はロールバックされます。そのため、例外をキャッチするときは、すべての例外情報をキャプチャする必要があります。

5. コントラクトを維持するために実装の詳細を非表示にする

場合によっては、例外をキャッチして別の例外を再スローする必要がある場合があります。これにより、スローされる例外のタイプは特定の例外である必要があります。次のコードを見てください:

FileStream fs = null;
            try
            {
                fs = FileStream();
              
            }
            catch (FileNotFoundException e)
            {
          //抛出一个不同的异常,将异常信息包含在其中,并将原来的异常设置为内部异常
                throw new NameNotFoundException();
            }
            catch (IOException e)
            {
 
               //抛出一个不同的异常,将异常信息包含在其中,并将原来的异常设置为内部异常
             throw new NameNotFoundException(); 
            } 
            finally 
            {
               if (fs != null) 
                { 
               fs.close(); 
            } 
            }

上記のコードは、処理メソッドを示しているだけです。スローされたすべての例外は、それらを「飲み込んで」新しい例外をスローするのではなく、メソッドの呼び出しスタックに渡される必要があります。型コンストラクターが例外をスローし、その例外が型コンストラクター メソッドでキャッチされない場合、CLR は内部で例外をキャッチし、代わりに新しい TypeInitialztionException をスローします。

2. DotNET 例外の一般的な処理メカニズム

在代码发生异常后,我们需要去处理这个异常,如果一个异常没有得到及时的处理,CLR会终止进程。在异常的处理中,我们可以在一个线程捕获异常,在另一个线程中重新抛出异常。异常抛出时,CLR会在调用栈中向上查找与抛出的异常类型匹配的catch块。如果没有任何catch块匹配抛出的异常类型,就发生一个未处理异常。CLR检测到进程中的任何线程有一个位处理异常,都会终止进程。

1.异常处理块

(1).try块:包含代码通常需要执行一些通用的资源清理操作,或者需要从异常中恢复,或者两者都需要。try块还可以包含也许会抛出异常的代码。一个try块至少有一个关联的catch块或finall块。       

(2).catch块:包含的是响应一个异常需要执行的代码。catch关键字后的圆括号中的表达式是捕获类型。捕获类型从System.Exception或者其派生类指定。CLR自上而下搜素一个匹配的catch块,所以应该教具体的异常放在顶部。一旦CLR找到一个具有匹配捕获类型的catch块,就会执行内层所有finally块中的代码,”内层finally“是指抛出异常的tey块开始,到匹配异常的catch块之间的所有finally块。

使用System.Exception捕捉异常后,可以采用在catch块的末尾重新抛出异常,因为如果我们在捕获Exception异常后,没有及时的处理或者终止程序,这一异常可能对程序造成很大的安全隐患,Exception类是所有异常的基类,可以捕获程序中所有的异常,如果出现较大的异常,我们没有及时的处理,造成的问题是巨大的。

(3).finally块:包含的代码是保证会执行的代码。finally块的所有代码执行完毕后,线程退出finally块,执行紧跟在finally块之后的语句。如果不存在finally块,线程将从最后一个catch块之后的语句开始执行。

备注:异常块可以组合和嵌套,对于三个异常块的样例,在这里就不做介绍,异常的嵌套可以防止在处理异常的时候再次出现未处理的异常,以上这些就不再赘述。

2.异常处理实例


(1).异常处理扩展方法

 /// <summary>
        ///  格式化异常消息
        /// </summary>
        /// <param name="e">异常对象</param>
        /// <param name="isHideStackTrace">是否隐藏异常规模信息</param>
        /// <returns>格式化后的异常信息字符串</returns>
        public static string FormatMessage(this Exception e, bool isHideStackTrace = false)
        {
            var sb = new StringBuilder();
            var count = 0;
            var appString = string.Empty;
            while (e != null)
            {
                if (count > 0)
                {
                    appString += "  ";
                }
                sb.AppendLine(string.Format("{0}异常消息:{1}", appString, e.Message));
                sb.AppendLine(string.Format("{0}异常类型:{1}", appString, e.GetType().FullName));
                sb.AppendLine(string.Format("{0}异常方法:{1}", appString, (e.TargetSite == null ? null : e.TargetSite.Name)));
                sb.AppendLine(string.Format("{0}异常源:{1}", appString, e.Source));
                if (!isHideStackTrace && e.StackTrace != null)
                {
                    sb.AppendLine(string.Format("{0}异常堆栈:{1}", appString, e.StackTrace));
                }
                if (e.InnerException != null)
                {
                    sb.AppendLine(string.Format("{0}内部异常:", appString));
                    count++;
                }
                e = e.InnerException;
            }
            return sb.ToString();
        }

(2).验证异常

 /// <summary>
        /// 检查字符串是空的或空的,并抛出一个异常
        /// </summary>
        /// <param name="val">值测试</param>
        /// <param name="paramName">参数检查名称</param>
        public static void CheckNullOrEmpty(string val, string paramName)
        {
            if (string.IsNullOrEmpty(val))
                throw new ArgumentNullException(paramName, "Value can&#39;t be null or empty");
        }

        /// <summary>
        /// 请检查参数不是空的或空的,并抛出异常
        /// </summary>
        /// <param name="param">检查值</param>
        /// <param name="paramName">参数名称</param>
        public static void CheckNullParam(string param, string paramName)
        {
            if (string.IsNullOrEmpty(param))
                throw new ArgumentNullException(paramName, paramName + " can&#39;t be neither null nor empty");
        }

        /// <summary>
        /// 检查参数不是无效,并抛出一个异常
        /// </summary>
        /// <param name="param">检查值</param>
        /// <param name="paramName">参数名称</param>
        public static void CheckNullParam(object param, string paramName)
        {
            if (param == null)
                throw new ArgumentNullException(paramName, paramName + " can&#39;t be null");
        }
        /// <summary>
        /// 请检查参数1不同于参数2
        /// </summary>
        /// <param name="param1">值1测试</param>
        /// <param name="param1Name">name of value 1</param>
        /// <param name="param2">value 2 to test</param>
        /// <param name="param2Name">name of vlaue 2</param>
        public static void CheckDifferentsParams(object param1, string param1Name, object param2, string param2Name)
        {
            if (param1 == param2) {
                throw new ArgumentException(param1Name + " can&#39;t be the same as " + param2Name,
                    param1Name + " and " + param2Name);
            }
        }

        /// <summary>
        /// 检查一个整数值是正的(0或更大)
        /// </summary>
        /// <param name="val">整数测试</param>
        public static void PositiveValue(int val)
        {
            if (val < 0)
                throw new ArgumentException("The value must be greater than or equal to 0.");
        }

(3).Try-Catch扩展操作

 /// <summary>
        ///     对某对象执行指定功能与后续功能,并处理异常情况
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="source">值</param>
        /// <param name="action">要对值执行的主功能代码</param>
        /// <param name="failureAction">catch中的功能代码</param>
        /// <param name="successAction">主功能代码成功后执行的功能代码</param>
        /// <returns>主功能代码是否顺利执行</returns>
        public static bool TryCatch<T>(this T source, Action<T> action, Action<Exception> failureAction,
            Action<T> successAction) where T : class
        {
            bool result;
            try
            {
                action(source);
                successAction(source);
                result = true;
            }
            catch (Exception obj)
            {
                failureAction(obj);
                result = false;
            }
            return result;
        }
        /// <summary>
        ///     对某对象执行指定功能,并处理异常情况
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="source">值</param>
        /// <param name="action">要对值执行的主功能代码</param>
        /// <param name="failureAction">catch中的功能代码</param>
        /// <returns>主功能代码是否顺利执行</returns>
        public static bool TryCatch<T>(this T source, Action<T> action, Action<Exception> failureAction) where T : class
        {
            return source.TryCatch(action,
                failureAction,
                obj => { });
        }
        /// <summary>
        ///     对某对象执行指定功能,并处理异常情况与返回值
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <param name="source">值</param>
        /// <param name="func">要对值执行的主功能代码</param>
        /// <param name="failureAction">catch中的功能代码</param>
        /// <param name="successAction">主功能代码成功后执行的功能代码</param>
        /// <returns>功能代码的返回值,如果出现异常,则返回对象类型的默认值</returns>
        public static TResult TryCatch<T, TResult>(this T source, Func<T, TResult> func, Action<Exception> failureAction,
            Action<T> successAction)
            where T : class
        {
            TResult result;
            try
            {
                var u = func(source);
                successAction(source);
                result = u;
            }
            catch (Exception obj)
            {
                failureAction(obj);
                result = default(TResult);
            }
            return result;
        }
        /// <summary>
        ///     对某对象执行指定功能,并处理异常情况与返回值
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <param name="source">值</param>
        /// <param name="func">要对值执行的主功能代码</param>
        /// <param name="failureAction">catch中的功能代码</param>
        /// <returns>功能代码的返回值,如果出现异常,则返回对象类型的默认值</returns>
        public static TResult TryCatch<T, TResult>(this T source, Func<T, TResult> func, Action<Exception> failureAction)
            where T : class
        {
            return source.TryCatch(func,
                failureAction,
                obj => { });
        }

本文没有具体介绍try,catch,finally的使用,而是给出一些比较通用的方法,主要是一般的开发者对于三个块的使用都有一个认识,就不再做重复的介绍。

以上就是关于.NET异常处理的思考(上)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。