6


1

読みづらいのフォーマット…​ try..catch..finallyブロック?

try..catch.finallyブロックをどのようにフォーマットしますか? 特に、少量のコードにラップするだけでは、すべての作業が中断され、コードが判読できなくなり、見苦しくなります。

例: + +

try
{
     MyService service = new Service();
     service.DoSomething();
     return something;
}
catch (Exception ex)
{
     LogSomething();
     return somethingElse;
}
finally
{
     MarkAsComplete();
     service.Dispose();
}

これらの7行のコードは16行の混乱になりました。

より良いtry..catch..最終的にフォーマットに関する何か提案はありますか?

11 Answer


6


実のところ、これは私にはよくわかります。 あなたの実際のコードがこのように見えるならば、私は本当にそれについて心配しないでしょう。 何が起こっているのかは明らかです。

実際のコードがもっと複​​雑な場合は、ブロックを適切な名前のメソッドに分割することを検討してください。


5


明示的な `+ Dispose()`の代わりに ` using `ブロックを使用できます。または、破棄する前にnullをチェックする必要がある場合は、 ` using +`ブロックがそれを行います。 残念ながら、ネスティングは増えています= /

try
{
     using(MyService service = new MyService())
     {
        service.DoSomething();
        return something;
     }
}
catch (SpecificException ex)
{
     LogSomething(ex);
     return somethingElse;
}
finally
{
     MarkAsComplete();
}


4


まあ、それはちょうどいいと思います。 これのいくつかは彼が中括弧の配置の議論をかき集めます。 あなたはこれをすることができます:

{//} catchを試してください(例外ex){//}、最後に{//}

私はあなたが持っているものを好む。 ただし、returnステートメントが1つだけになるようにコードを修正することを検討してください。 私はそれがもう少し良いデザインだと思います。


2


同じ行に角括弧を付けてコードをフォーマットします。

{MyService service = new Service();を試してください。 service.DoSomething();何かを返す。 catch(Exception ex){LogSomething();}何かを返します。 {MarkAsComplete();} service.Dispose(); }

間隔を広げたい場合は、空白行を追加することをお勧めします。 これは、コードの論理ブロック間の区切り文字としても機能します。


2


あなたはコンテナ(非常にスマートな工場)とアドバイス(すべての面倒な詳細を処理するために)について考えるかもしれません。

Dear Mr. Container Sir,
Whenever I request from you an instance object of the interface ISomething,
    please construct for me an instance of the concrete class SomethingImpl;
    in addition, please see to it (however you do it) that, whenever I call a
    method on this instance, it is wrapped within a complicated and messy try-
    catch-finally which logs exceptions and mark calls as completed. That way,
    all I have to do is write the business logic that goes into the SomethingImpl
    and I don't have to worry about all the messy infrastuctural details.
Sincerely,
Mr. Agile.

これは、コードでは、次のようになります。

//a class that knows how to take care of the messy infrastructure details
public class MyMessyInterceptor : IInterceptor {
    public void Intercept(IInvocation invocation) {
        //handle the messy details of continuing with the method-invocation,
        //but within a try-catch-finally that includes exception handling and
        //call logging.
    }
}

//a function that will configure a container (very smart factory)
public IContainer CreateContainer() {
    var builder = new ContainerBuilder();

    //tell the container-builder about the interceptor
    builder
        .Register(c => new MyMessyInterceptor())
        .Named("keep-my-code-clean")
    ;

    //tell the container what to do when you ask it for a ISomething
    builder
        .Register()
        .As()
        .InterceptedBy("keep-my-code-clean")
    ;

    return builder.BuildContainer();
}

//some function out there in your code somewhere that needs to make a
//service call; there's hundreds of functions out there just like this
//in your code, and they all just got much simpler
public object GottaGoDoSomething() {
    //find the container
    var container = GetTheSingletonContainerObject();
    //ask for an instance of ISomething - it knows to provide a
    //SomethingImpl wrapped in an interceptor that takes care of all
    //the logging and exception handling
    var something = container.resolve();
    //call the big method
    return something.DoSomething();
    //magically (not really), the exception handling and logging are
    //already taken care of
}

インターセプタークラスを思いつくのは一度だけです。 各インターセプターとサービスクラスの登録も一度だけ行われます。 コンテナのセットアップ(非常にスマートな工場)は確かに複雑です。

しかし、サービスオブジェクトを使用しなければならず、例外処理やロギングなどの複雑で面倒なインフラストラクチャの詳細にその使用を埋め込む必要があるコード内のすべての場所は、非常にクリーンで複雑ではありません。 `+ CreateContainer `は1つしかありませんが、何百もの ` GottaGoDoSomething +`があるため、少し複雑ですが、非常に簡単です。

(注:コード例では、AutofacコンテナフレームワークとCastleインターセプタフレームワークを使用しています。 これは依存性注入パターンではなく、サービスロケーションパターンの例であることを認識していますが、重要なのは、依存性注入を説明するためではなく、インターセプターを説明してコンテナーに登録することです。


1


空白です。 最低限のこととして、各returnステートメントの前と、コードの「実行」セクションと「変数の作成」セクションの間には、必ず1行の空白を入れます。

{MyService service = new Service();を試してください。

service.DoSomething();

何かを返す。

catch(Exception ex){LogSomething();}

何かを返します。

{MarkAsComplete();} service.Dispose(); }

ずっといい。


0


私はあなたのフォーマットもうまく読めると思います。 私の提案は、 `+ catch +`ステートメントを控えめに使用することです。 あなたが実際に何かを捕まえる必要があるときだけそれを使ってください。 そうでなければ、プログラムの他の部分に例外を処理させることができます。 全体としての「初期の失敗」の概念。

try
{
    //do something that may throw an exception.
}
finally
{
    //handle clean up.
}

//let a method further down the stack handle the exception.


0


個人的には、私は自分のコードで前述のスタイルに従う傾向があります…​ それはコメントをする余地を与えて、そして私の論理の流れをよりよく示します。

私はワイドスクリーンを使っていますが、空白はいろいろなコラムをうまく並べることができ、それほど傷つけることはありません。

試してみる{//サービスを受ける

MyService service = new Service(); service.DoSomething();

何かを返す。

}

catch(Exception ex){//サービスがいっぱいになっている可能性がある/タイムアウトしたという事実

LogSomething();

何かを返します。

}

最後に{//サービスがまだ保持している可能性のあるリソースをすべて削除します。

MarkAsComplete(); service.Dispose();

}


0


私も、あなたが最初に持っていたもののように。 .csファイル内の物理行には何もかかりませんし、最終的な出力コードを変更することもありません。 だからあなたやあなたのチームに最高の読みやすさを提供するためにあなたが必要とするすべてを使いなさい。

実際、自分自身や他の人のためにコメントを追加することによって、コーディングするときにここに表示されている16行よりも多くの行を実際に使用するようにしてください。

追加して

// a comment that says what's going on

6か月後に戻ってきたときに、このTry.Catchが何をしているのかをよく思い出すことができます。


0


私は常にtry catchブロックをすべて試してリファクタリングし、それらを独自のメソッドにカプセル化します。

これは常にすべてをより読みやすくするように思われます、それに加えて、あなたのメソッドに一つのことだけをさせるのは良いプログラミング習慣です。 あなたのtry-catch-finally文の上と下にコードがある場合、それは複数のことをやっているということです。