2009-08-13 3 views
10

は、以下のメソッドシグネチャを検討:この良いC#スタイルですか?

  • は、ポーリングオブジェクトのリストを生成するためにデータベースにアクセス:

    public static bool TryGetPolls(out List<Poll> polls, out string errorMessage) 
    

    この方法は、以下を実行します。

  • が成功し、errorMessageが空の文字列になる場合はtrueを返します。
  • が成功しなかった場合はfalseを返し、errorMessageには例外メッセージが含まれます。

このスタイルはいいですか?

更新:

public static List<Poll> GetPolls() 

及びその方法で

が、それはすべての例外をキャッチしない(ので、私は例外をキャッチするために、発信者に依存): は、私は、次のメソッドのシグネチャを使用しないと言うことができます。どのように私はそのメソッドの範囲にあるすべてのオブジェクトを処分して閉じますか?例外がスローされるとすぐに、メソッド内のオブジェクトを閉じて破棄するコードにはアクセスできなくなります。この方法は、3つの異なる事をやろうとしている

+1

コードを書式設定するには、その前に4つのスペースを追加します。最も簡単な方法は、コードを入力/コピーし、すべてを強調表示し、エディタで[コード]ボタンをクリックすることです。 –

答えて

43

  1. が成功
  2. リターンにのエラーメッセージ

を示すブール値をポーリング

  • リターンのリストを取得して返しますデザインの観点からはかなり乱雑です。

    より良いアプローチは、単純に宣言するために、次のようになります。

    public static List<Poll> GetPolls() 
    

    その後、何かがうまくいかない場合は、この方法はExceptionを投げてみましょう。

  • +3

    TryGetPollを持つと、正当に何も返さない場合に便利です。 – Michael

    +0

    +1クリーンなソリューションの場合 –

    +4

    @Michael:「試してみてください」という方法は、何かが間違っているかもしれないが気にしない(具体的には多かれ少なかれ)場合に適しています。正当に何も返さない場合は、null/Nothingを返す必要があります。 – STW

    11

    私は

    public static bool TryGetPolls(out List<Poll> polls) 
    

    がより適切であろうと信じています。メソッドがTryGetの場合、私の最初の仮定は失敗すると予想する理由があり、次は何をすべきかを決定するために呼び出し元にあります。呼び出し元がエラーを処理していないか、エラー情報が必要な場合は、対応するGetメソッドを呼び出すと考えられます。

    +0

    IList を使用すると、抽象度が向上します。 –

    7

    一般的に、私はいいえと言います。

    TryGetXを実行してbooloutパラメータを返しているため、実際にはノーと言う理由はありません。私はエラー文字列を返すので、それは悪いスタイルだと思います。

    Tryは、一般的に発生した特定のエラーを無視する必要があります。他の問題も、適切な例外メッセージで例外をスローする可能性があります。このようなTryメソッドの目標は、特定の単一の種類の障害が頻繁に発生しないと予想される場合にスローされた例外のオーバーヘッドを避けることです。ユーザーが適切なだとGetPollsTryGetPollsの観点で実施することができる何ができる

    public static bool TryGetPolls(out List<Poll> polls); 
    public static List<Poll> GetPolls(); 
    

    この方法:

    代わりに、あなたが探しているのは、メソッドのペアです。私はあなたのstaticのネスが文脈で意味をなさないと仮定しています。

    7

    は戻って考えてみましょう:

    • 空のコレクション
    • ヌル

    うち複数のパラメータを、私には、code smellです。このメソッドは、1つだけ行う必要があります。これは、エラーメッセージが何であるかに依存し

    throw new Exception("Something bad happened"); 
    //OR 
    throw new SomethingBadHappenedException(); 
    
    +1

    +1:また、特定の条件で失敗するという既知のケースに対してカスタム例外を実装することも検討してください。 –

    +0

    しかし、より正確にエラーの種類に適合するSystem.Exceptionよりも具体的なものを投げてください。 –

    +0

    ありがとうIan。それはある種の例外がスローされるべきであるという指針としてのものであることを意味しました。コードの浴室壁からの文字通りのコピー/ペーストではありませんでした。 :) –

    1

    は、とのエラーメッセージを高め、取り扱いを検討してください。たとえば、データベース接続が利用できないなどの理由で処理を続行できない場合、他の人が言及したように例外をスローする必要があります。

    ただし、試行についての「メタ」情報を返すだけでよい場合は、単一のメソッド呼び出しから複数の情報を返す方法が必要です。その場合は、リスト< Poll> PollsとErrorMessageという2つのプロパティを含むPollResponseクラスを作成することをお勧めします。次に、メソッドにPollResponseオブジェクトを返します。

    +0

    これは元のコードIMHOと同じように非観念的です。慣用句C#は、エラーメッセージを含むカスタムオブジェクトではなく、エラーをレポートするために例外を使用します。 –

    +3

    ここのスコットのテクニックはSystem.Web.HttpResponseと似ているかもしれません。私は、Pollオブジェクトのコレクションを処理することが、エラー、言語、有効期限、ユーザーの可視性レベルなどを扱うまったく新しいオブジェクトを保証するかもしれないという不公平な仮定はないと思います。 –

    +0

    @グレッグ - 私はそれが本当に何errorMessageになると思う。誰もがここではプログラムの例外だと仮定していますが、必ずしもそうであるとは限りません。プログラム例外とは、実行を継続できないことを意味します。例外とエラーは同じものではありません。ユーザーが数字フィールドに文字を入力しようとすると、それはエラーですが、例外をスローする必要はありません。この場合、「エラー」は、ポーリングデータが古くなっているか、結果が100%にならないことがあります。私は「関数呼び出しから2つのものを返すにはどうすればよいの? –

    0

    エラーが一般的な発生かどうか、まったく例外であるかどうかによって異なります。

    エラーが非常に稀で悪い場合は、メソッドがポーリングのリストを返し、エラーが発生した場合には例外をスローすることを検討するとよいでしょう。

    int.TryParseメソッドで文字列を整数に変換する際のエラーのように、エラーが通常の操作では実際に共通する部分である場合は、作成したメソッドが適切です。

    私は前者がおそらくあなたにとって最良の場合だと思います。

    +0

    2番目のケースでは、yshuditeluのアドバイスを使用する以外は、すべての理由に同意します。元のコード – Brian

    +0

    「希少性」が正しいコンセプトだとは思わない。 「例外的」はより正確です。数字を文字列として引数として受け取る関数を考えてみましょう。文字列が数字でない場合、それは例外的なケースですが、必ずしも稀ではありません。 –

    11

    これは間違いなくC#を記述する慣用的な方法ではありません。これは、おそらくそれもおそらく良いスタイルではないことを意味します。

    TryGetPollsメソッドを使用している場合は、操作が成功すると結果が必要であることを意味し、失敗した場合は失敗した理由を気にしません。

    単純にGetPollsメソッドがある場合は、結果が常に得られることを意味し、成功しない場合は、Exceptionの形式で理由を知りたいと考えます。

    2つを混在させると、その中間になります。これはほとんどの人にとって珍しいことです。だから私はエラーメッセージを返さないか、失敗したらExceptionを投げると言うでしょうが、この奇妙なハイブリッドアプローチを使用しないでください。

    だからあなたのメソッドのシグネチャは、おそらくどちらかでなければなりません:

    IList<Poll> GetPolls(); 
    

    または

    bool TryGetPolls(out IList<Poll> polls); 
    

    (それも良いことだと、私はあまりにも、いずれの場合もIList<Poll>ではなくList<Poll>を返してることに注意してください実装より抽象にプログラムする練習)

    +0

    Greg、これは優れた点です。 –

    +0

    +1のIList - 私はあまりにもそれを言及する必要があります。 –

    +0

    私は、特にクライアントがあなたのコントロールにない場合は、パブリックAPIの抽象化のためにすべてです。しかし、これが内部クラスであれば、.NetフレームワークのList実装を何か他のものに置き換える可能性があります。それはあなたが十分な公正な模倣できるインターフェイスでしたが、.Net Listクラスですか? KISSの原則はどうですか? – softveda

    2

    いいえ、私の視点からは、これは非常に悪いスタイルです。

    呼び出しが失敗した場合は、例外をスローし、例外にエラーメッセージを入れてください。これが例外で、あなたのコードはより洗練され、読みやすく、維持しやすくなります。

    0

    方法が失敗する頻度によって異なります。一般に、.NetのエラーはExceptionと通信する必要があります。そのルールが成立しない場合は、エラー条件が頻繁に発生し、throwのパフォーマンスの影響が大きすぎる場合です。

    データベースタイプの作業については、Exceptionが最適です。

    0

    私はこのように言いたいと思います。

    public static List<Poll> GetPolls() 
    { 
        ... 
    } 
    

    それがポーリングを取得するために失敗した場合、それはおそらく(にErrorMessageを)例外をスローする必要があり、加えてこれはアウトパラメータを扱うよりも少ない厄介であるメソッドチェーンが可能になります。

    FxCopを実行する場合は、リストをIListに変更して、幸せにしたいと思うでしょう。

    1

    実際には、これにはいくつかの問題があります。

    まず、このメソッドは、通常、成功すると思われるように聞こえます。エラー(データベースに接続できず、pollsテーブルにアクセスできないなど)はまれです。この場合、例外を使用してエラーを報告する方がはるかに合理的です。 Try...パターンは、通話が「失敗」することが多いと考えられます。文字列を整数に解析すると、文字列が無効である可能性が高いので、これを処理するための速い方法が必要です。したがって、TryParse。これはここでは当てはまりません。

    第2に、エラーの有無を示すboolの値と文字列メッセージとしてエラーを報告します。呼び出し元は、さまざまなエラーをどのように区別しますか?彼は確かにエラーメッセージのテキストで一致することはできません - それは変更の対象となる実装の詳細であり、ローカライズすることができます。そして、「データベースに接続できません」(この場合はデータベース接続設定ダイアログを開いてユーザーに編集させてもよいでしょうか?)と「データベースに接続しましたが、「アクセスが拒否されました」 "あなたのAPIはそれらを区別する良い方法を与えません。

    メッセージを報告するには、bool + out stringではなく例外を使用してください。一度それを行うと、out引数を必要とせずに、戻り値としてList<Poll>を使用することができます。もちろん、パターンのためにTry...が予約されているので、メソッドの名前をGetPollsに変更します。

    0

    いいですね。でも、私は希望:

    enum FailureReasons {} 
    public static IEnumerable<Poll> TryGetPolls(out FailureReasons reason) 
    

    ので、エラー文字列が

    0

    C#のメソッドは、実際には一つのことを行う必要があります...データ・アクセス・コードに住んでいません。あなたはその方法で3つのことをしようとしています。私は他の人が示唆しているようにして、エラーがあれば例外をスローします。別のオプションは、Listオブジェクトの拡張メソッドを作成することです。

    公共の静的なクラスで:

    List<Poll> polls = new List<Poll>().Fill(); 
    if(polls != null) 
    { 
        // no errors occur 
    } 
    

    編集:

    その後
    public static List<Poll> Fill(this List<Poll> polls) { 
        // code to retrieve polls 
    } 
    

    、これを呼び出すために、あなたのような何かをするだろう私はちょうどこのを作りました。あなたは新しい演算子が必要な場合があります。List<Poll>().Fill()

    0

    あなたの前提条件、制約条件、欲望/目標、および推論を記載してください。私たちは、あなたの意図が何であるかを知るためにあなたの心を推測し、そして/または読む必要があります。ポーリングリストオブジェクト

  • を作成するには、

    • にあなたの関数をしたいと仮定し

      は、すべての例外

    • を抑制ブール
    • で成功を示すと失敗
    上の任意のエラーメッセージを提供

    上記の署名は問題ありません(すべての可能な例外を飲み込むのは良いpではありませんがラクティス)。

    一般的なコーディングスタイルとして、他にも言及しているように、いくつかの潜在的な問題があります。

  • 1

    ガイドラインは、彼らが(メソッドのこれ以上のチェーンを使用しないために困難APIを作るために、開発者が前にすべての変数を宣言する必要があり、それらが絶対的に必要とされていない場合REF outパラメータを回避しようとすると言いますまた、エラーコードやメッセージを返すことはベストプラクティスではありません、ベストプラクティスは、例外とエラー報告のための例外処理を使用することです)

    のメソッドを呼び出して、他のエラーは無視することは容易になり、より多くの仕事は、エラーを渡すことがあります情報を収集し、同時にスタックトレースや内部例外などの貴重な情報を失うことになります。

    メソッドを宣言するためのより良い方法は次のとおりです。

    public static List<Poll> GetPolls() ... 
    

    やエラーのための多くのWin32関数に見られるように、このパターンは、もあり

    try 
    { 
        var pols = GetPols(); 
        ... 
    } catch (DbException ex) { 
        ... // handle exception providing info to the user or logging it. 
    } 
    
    0

    を扱う使用例外を報告します。

    public static bool GetPolls(out List<Poll> polls) 
    
    
    if(!PollStuff.GetPolls(out myPolls)) 
        string errorMessage = PollStuff.GetLastError(); 
    

    しかし、IMOは恐ろしいです。 私は、このメソッドが3dゲーム物理エンジンまたはsometingで毎秒65回実行されなければ、何か例外をベースにしています。

    0

    私はここで何かを見逃しましたか?質問者は、メソッドが失敗した場合にリソースをクリーンアップする方法を知りたいと思うようです。

    public static IList<Poll> GetPolls() 
    { 
        try 
        { 
        } 
        finally 
        { 
         // check that the connection happened before exception was thrown 
         // dispose if necessary 
         // the exception will still be presented to the caller 
         // and the program has been set back into a stable state 
        } 
    } 
    

    デザイン上の注意点では、このメソッドをリポジトリクラスにプッシュして、メソッドを理解するための何らかのコンテキストがあると考えています。アプリケーション全体は、おそらく、データストアの責任であるべき、世論調査の保管と取得に責任を負いません。

    関連する問題