0

Delphiでは、次のようなことができます:

try
  if not DoSomething then
    Exit;
  if not DoSomething2 then
    Exit;
  if not DoSomething3 then
    Exit;

finally
  DoSomethingElse;
end;

別の方法では、メソッドのDoSomething結果が false の場合、プログラム フローは finally ブロックに転送され、実行さDoSomething2DoSomething3ません。

C#でそのような動作を実現するにはどうすればよいですか?

前もって感謝します。

Edit1: 以下の例は VS 2008 ではコンパイルされません

Edit2:申し訳ありませんが、断食して return ステートメントを忘れてしまいました。

XElement OrderStatus(q_order_status Request)
{
  XElement Response;
  try
  { 
    if (DoSomething() != 0 )
    {
      return;
    }
  }
  catch(Exception e)
  {
    // catch some errors and eventually pass the e.Message to the Response
  }
  finally
  {
    Response =  new XElement("SomeTag", "SomeResponse");
  }
  return Response;
}

Edit3:DoSomething1テスト後、これを達成する最も簡単な方法は、結果が false の場合に例外をスローすることです。独自の例外をスローし、特定のメッセージを書き込んで、finally 句に渡すことができます。

4

10 に答える 10

14

フロー制御に例外処理構造を使用するべきではありません。つまり、C# にExit匹敵します。return[return キーワード][1] に関する MSDN ドキュメントには次のように書かれています。

return ステートメントが try ブロック内にある場合、finally ブロックが存在する場合は、コントロールが呼び出し元のメソッドに戻る前に実行されます。

一般に、対応する-block に達したfinally場合、 -block はほとんど常に実行されます。-blocktryの実行を保証できない状況がまれにいくつかありますが、それらはすべて致命的なエラーであり、プログラムがすぐにクラッシュする可能性があります。finally

コードが C# でどのように見えるか:

try
{
    if (!DoSomething())
        return;

    if (!DoSomething2())
        return;

    if (!DoSomething3())
        return;
}
finally
{
    DoSomethingElse();
}

しかし、繰り返しますが、これをしないでください。通常のフロー制御ではなく、例外の処理を目的としていtryます。finally

あなたの編集に返信してください:メソッドの戻り値の型が であり、戻り値の型が の場合にのみ使用できるため、
コードreturnではコンパイルされません。を使用することもできますが、それは がとにかく行うことでもありますし、以前に割り当てて を実行することもできます。XElementreturnvoidreturn new XElement("SomeTag", "SomeResponse");finallyResponsereturn Response;

finallyは常に実行されますが、理由が-blockreturn Response;に入った場合に実行されないのは、 -block内で実行したためであることに注意してください。finallyreturntry

于 2009-10-21T08:06:25.850 に答える
3

更新された質問への回答:

エレガントな方法でこれを行うのに問題がある理由は、戻り値と例外の組み合わせを使用しているように見えるためです。状況が例外的な場合は、戻り値を使用する代わりに手動で例外を発生させることを検討する必要があります。

ただし、戻り値に十分な理由があると仮定すると、finallyブロックを完全に使用せずに、ブロックreturnの最後とtryブロックに a を含める方が明確になると思いますcatch。これにより、面倒な方法で例外メッセージを渡す必要がなくなります。

ResponseDoSomething() がゼロ以外の値を返す場合のコード スニペットが表示されないため、最善の解決策が何であるかは実際には言えません。


元の答え:

何を達成しようとしているのかによって少し異なります。メソッドのいずれかで実際に例外がスローされていますか? try-finallyそうでなければ、パターンを使用する正当な理由はありません。これは同等です(ただし、読みやすくするためにはお勧めできません)。

bool doneEverything = DoSomething() && DoSomething2() && DoSomething3();
DoSomethingElse();

例外がスローされ、より高いレベルで処理される場合は、このコードを別のメソッドに分離することをお勧めします。これにより、returnステートメント* を使用できます。

void DoStuff()
{
    try
    {
        if (!DoSomething())
            return;

        if (!DoSomething2())
            return;

        if (!DoSomething3())
            return;
    }
    finally
    {
        DoSomethingElse();
    }
}

finallyコードブロックがいつ実行されるかについての質問に答えるには、実行中のスレッドが途中で終了しない限り、常に実行されます。

*: Delphi に相当するものがないため、再構築をお勧めしExitます。ステートメントは最も近くにありますが、ループ構造またはブロックbreakでのみ使用できます。switch終了動作を模倣するにはgoto、ラベルが必要です。私たちはそれを望まないでしょう。:)

于 2009-10-21T08:19:54.530 に答える
2

C# では、try ステートメント内で return が呼び出されると、finally も実行されます。

bool doSomething = false; bool doSomething2 = true;

        try
        {
            if( !doSomething )
            {
                Console.WriteLine ("not dosomething");
                return;
            }
            if( !doSomething2 )
            {
                Console.WriteLine ("not dosomething 2");
                return;
            }
        }
        finally
        {
            Console.WriteLine ("In finally");
        }
于 2009-10-21T08:14:22.963 に答える
2

もちろん、switch ケースについてはどうですか? もし、c# で finally ブロックと言って、finally を意味しないのであれば。デフォルトのケースはfinallyブロックで、フロー制御の例とここmsdnでも見つけることができます:Flow Control (C# vs. Java)

static void Main(string[] args)
{
    switch (args[0])
    {
        case "copy":
            //...
            break;

        case "move":
            //...
            goto case "delete";

        case "del":
        case "remove":
        case "delete":
            //...
            break;

        default:
            //...
            break;
    }
}
于 2009-10-21T08:31:02.637 に答える
2

3 つの try 行を共通の if/else ブロックにしないのはなぜですか? 終了する代わりに、DoSomethingElse を呼び出します。そのようです:

if (DoSomething() == false)
{   
    DoSomethingElse();
}
else if (DoSomething2() == false)
{
    DoSomethingElse();
}
else if (DoSomething3() == false)
{
    DoSomethingElse();
}

「C# は Delphi ではない」と言いたいのですが、それは少し傲慢です。

于 2009-10-21T08:08:26.843 に答える
1

この種の状況では、例外処理以外のケースのみを扱うものとして質問を理解すると、次のように、の内容をtryプライベート ヘルパー メソッドにリファクタリングします。

void BranchOnContext()
{
        if (!DoSomething())
            return;

        if (!DoSomething2())
            return;

        // last one will drop out and return anyway
        DoSomething3();
}

void DoStuff()
{
    BranchOnContext();  // Assumed not to throw
    DoSomethingElse();  // Always the next thing to be executed
}

編集 -- 変更された要件の追跡

void DoStuff()
{
    string message = string.Empty;
    try {
        BranchOnContext();
    } catch (MyExpectedException me) { // only catch exceptions I'm prepared to handle
         message = me.Message;
    }  
    DoSomethingElse(message);  // Always the next thing to be executed
}
于 2009-10-21T08:34:45.357 に答える
0

これはデルフィを複製しているようです:-

try
{
  if(DoSomething())
    if(DoSomething2())
      DoSomething3();
}
finally
{
  DoSomethingElse();
}

別のスタイル(このスタイルを嫌う人もいれば、好きになる人もいます。):-

try
{
  DoSomething() && DoSomething2() && DoSomething3();
}
finally
{
  DoSomethingElse();
}

でも、他の行動が欲しいという印象を受けますか?

後藤バージョン?

try
{
  if (!DoSomething())
    goto Exit;

  if (!DoSomething2())
    goto Exit;

  if (!DoSomething3())
    goto Exit;

Exit:;
}
finally
{
  DoSomethingElse();
}

イライラすることに注意してください; ラベルの後、ラベルはステートメントの前になければならないようです。

エピファニーがありました:-

Func<bool>[] somethings = new Func<bool>[] {DoSomething, DoSomething2, DoSomething3};
try
{
  foreach (Func<bool> something in somethings)
  {
    if (!something())
      break;
  }
}
finally
{
  DoSomethingElse();
}
于 2009-10-21T14:39:13.187 に答える
0

最初に示した Delphi のものと動作が非常に似ていることがわかりました。私はあなたのコメントに興味があります。ResponseDoSomethings の結果に依存します。

XElement OrderStatus(q_order_status Request)
{
  XElement Response;
  int result = 0;
  string Message = "";
  try
  { 
    result = DoSomething1();
    if (result != 0)
    {
      throw new DoSomethingException("DoSomething1 has failed!");
    }
    result = DoSomething2();
    if (result != 0)
    {
      throw new DoSomethingException("DoSomething2 has failed!");
    }
    result = DoSomething3();
    if (result != 0)
    {
      throw new DoSomethingException("DoSomething3 has failed!");
    }
    Message = "All tests has been passed.";
  }
  catch(DoSomethingException e)
  {
    Message = e.Message;
  }
  catch(Exception e)
  {
    Message = e.Message;
  }
  finally
  {
    Response =  new XElement("SomeTag", Message);
  }
  return Response;
}

どう思いますか?

于 2009-10-21T17:38:03.713 に答える
0
void funcA()
{
    if (!DoSomething())
        return;

    if (!DoSomething2())
        return;

    if (!DoSomething3())
        return;
}

void funcB()
{
    funcA();
    DoSomethingElse;
}
于 2009-10-21T17:54:38.953 に答える
0

更新された情報でこれに別のクラックを取ります:

DoSomethingElse を常に実行し、可能な例外からのメッセージを含めたい

DoSomething のいずれかが 0 を返す場合、null が返されます。そうでない場合は、汎用メッセージが作成されます。例外があった場合は、キャッチされ、その情報を含むメッセージが返されます。これはどう?

XElement OrderStatus(q_order_status Request)
{
  try
  { 
    if (DoSomething() != 0 )
    {
      return null;
    }
    else
    {
      return new XElement("SomeTag", "SomeResponse");
    }
  }
  catch(Exception e)
  {
    // catch some errors and eventually pass the e.Message to the Response
    return new XElement(e.tag, e.response);
  }
}

私はまだ良い意味でこれに入れる方法に苦労していますfinally

于 2009-10-21T10:47:16.593 に答える