33

私は次のような方法を持っています:

int f() {
  try {
    int i = process();
    return i;
  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
}

これにより、「すべてのコード パスが値を返すわけではありません」というコンパイラ エラーが発生します。しかし、私の場合、ThrowSpecificFault() は常に (適切な) 例外をスローします。だから私は最後に戻り値を置くことを余儀なくされていますが、これは醜いです。

そもそもこのパターンの目的は、「process()」が外部 Web サービスへの呼び出しであるが、クライアントの予想されるインターフェイス (~facade パターンだと思います) に一致するようにさまざまな異なる例外を変換する必要があるためです。

これを行うためのよりクリーンな方法はありますか?

4

13 に答える 13

71

に変換することをお勧めしThrowSpecificFault(ex)ますthrow SpecificFault(ex)。メソッドは、SpecificFaultそれ自体をスローするのではなく、スローされる例外オブジェクトを返します。ずっときれい。

これは、 Microsoft のガイドラインで推奨されているパターンです。

于 2010-10-08T17:41:27.427 に答える
9

現在、戻り型は型、または「戻り型なし」を意味する「void」にすることができます。理論的には、必要なセマンティクスを持つ 2 番目の特別な戻り値の型「never」を追加できます。"never" を返すメソッドへの呼び出しで構成される式ステートメントの終点は、到達不能と見なされるため、"goto"、"throw"、または "return" が有効な C# のすべてのコンテキストで有効です。 .

これが 10 年後の現在の型システムに追加される可能性は非常に低いです。次に型システムをゼロから設計するときは、忘れずに「never」型を含めてください。

于 2010-10-08T19:37:15.857 に答える
8

The problem here, is that if you go into the catch block in f() your function will never return a value. This will result in an error because you declared your function as int which means you told the compiler that your method will return an integer.

The following code will do what you are looking for and always return an integer.

int f() {
  int i = 0;
  try {
    i = process();

  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
  return i;
}

put the return statement at the end of your function and you will be fine.

アプリケーションの実行パスに関係なく、メソッドが常に値を返すようにすることをお勧めします。

于 2010-10-08T17:40:30.580 に答える
5

次のようにできます。

catch (Exception ex)
{
    Exception e = CreateSpecificFault(ex);
    throw e;
}
于 2010-10-08T17:42:41.650 に答える
3

いいえ。

ThrowSpecificFault別の DLL で定義されていると想像してください。例外をスローしないように DLL を変更し、プログラムを再コンパイルせずに実行するとどうなりますか?

于 2010-10-08T17:40:17.587 に答える
3

次の 3 つのオプションがあります。

常に i を返しますが、事前に宣言します。

int f() {
    int i = 0; // or some other meaningful default
    try {
        i = process();
    } catch(Exception ex) {
        ThrowSpecificFault(ex);
    }
    return i;
}

メソッドから例外を返し、それをスローします。

int f() {
    try {
        int i = process();
        return i;
    } catch(Exception ex) {
        throw GenerateSpecificFaultException(ex);
    }
}

または、カスタム Exception クラスを作成し、それをスローします。

int f() {
    try {
        int i = process();
        return i;
    } catch(Exception ex) {
        throw new SpecificFault(ex);
    }
}
于 2010-10-08T17:41:28.850 に答える
1

どうですか:

int f() {
 int i = -1;
 try {
   i = process();       
 } catch(Exception ex) {
   ThrowSpecificFault(ex);
 }
 return i;
}
于 2010-10-08T17:41:18.633 に答える
0

はい。

ThrowSpecificFault() が例外をスローするとは思わないでください。例外を返してから、ここにスローします。

実際にはもっと理にかなっています。「通常の」フローでは例外を使用しないため、毎回例外をスローすると、その例外がルールになります。関数で特定の例外を作成し、ここでのフローの例外であるため、ここでスローします。

于 2010-10-08T17:41:36.870 に答える
0

私は、ThrowSpecificFault に Object を返させることができると思います。

return ThrowSpecificFault(ex)

それ以外の場合は、ThrowSpecificFault を Exception サブタイプのコンストラクターとして書き直すか、ThrowSpecificFault を単に例外を作成するがスローしないファクトリにすることができます。

于 2010-10-08T17:41:48.740 に答える
0

あなたの場合、それはコンパイラーではなくあなたの知識です。このメソッドは確かに厄介な例外をスローすると言う方法があります。

これを試して

int f() {
  try {
    return process();
  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
  return -1;
}

throw キーワードを使用することもできます

int f() {
  try {
    return process();
  } catch(Exception ex) {
    throw ThrowSpecificFault(ex);
  }
}

ただし、そのメソッドは例外をスローするのではなく、何らかの例外を返す必要があります。

于 2010-10-08T17:44:41.490 に答える
0

Unity.Interception を使用してコードをクリーンアップします。傍受処理を使用すると、コードは次のようになります。

int f() 
{
    // no need to try-catch any more, here or anywhere else...
    int i = process();
    return i;
}


次のステップで行う必要があるのは、インターセプション ハンドラーを定義することだけです。これは、例外処理用にカスタマイズできます。このハンドラーを使用すると、アプリでスローされたすべての例外を処理できます。利点は、すべてのコードを try-catch ブロックでマークアップする必要がなくなったことです。

public class MyCallHandler : ICallHandler, IDisposable
{
    public IMethodReturn Invoke(IMethodInvocation input, 
        GetNextHandlerDelegate getNext)
    {
        // call the method
        var methodReturn = getNext().Invoke(input, getNext);

        // check if an exception was raised.
        if (methodReturn.Exception != null)
        {
            // take the original exception and raise a new (correct) one...
            CreateSpecificFault(methodReturn.Exception);

            // set the original exception to null to avoid throwing yet another
            // exception
            methodReturn.Exception = null;
        }

        // complete the invoke...
        return methodReturn;
    }
}

ハンドラーへのクラスの登録は、構成ファイルを介して、またはプログラムで行うことができます。コードはかなり単純です。登録後、次のように Unity を使用してオブジェクトをインスタンス化します。

var objectToUse = myUnityContainer.Resolve<MyObjectToUse>();

Unity.Interception の詳細:

http://msdn.microsoft.com/en-us/library/ff646991.aspx

于 2010-10-08T17:50:49.870 に答える