2011-08-05 4 views
3

時には評価に失敗する可能性のある関数を処理する最善の方法はありますが、失敗しても親ルーチンを停止する必要はありませんが、ユーザーに説明が必要な場合がありますか?メソッド内でユーザーメッセージを生成して処理しますか?

私はコードの中に深い番号を返すような関数を持っています。 Codingwiseでは、最も簡単な方法は、関数をnull可能にし、評価できないときはnullを返すことです。こうすることで、呼び出し元のルーチンは、関数が数値を返さなかったことを知りながら続けることができます。

しかし、場合によっては、ユーザーに不具合の理由を表示して、何を修正するかを知りたい場合があります。明らかにnullを返すだけでは十分な情報ではありません。匿名のリスナーがキャッチするかどうかを評価するときに、関数自体の内部でメッセージを生成し、必要に応じて表示する必要がありますか?
(論理関数がユーザーメッセージの作成に責任を負うべきでないことを正当に指摘している人には、関数がフルテキストメッセージを生成することを意味するわけではなく、それをメッセージに解析する)

他のオプションは、評価できない場合は関数内で例外をスローし、必要に応じてユーザーのメッセージにキャッチして解釈します。しかし、述べられているように、評価できないことは一般的にルーチンの停止を意味するものではなく、今度はTry ... Catchブロックを関数呼び出しの周りに置かなければならないでしょう。

+0

「TryX」パターンはおそらくこれのための最良の解決策だと思います。そうすれば、ルーチンを停止する心配なしに関数を呼び出すことができ、必要に応じて失敗理由を得ることができます。成功/失敗情報を含むようにリターン・セットを拡張する提案された解決策もおそらく機能しますが、私は個人的にそれが頻繁に使用されるのを見ておらず、リターンを少し面倒に扱うかもしれません。 – Tekito

答えて

1

outパラメータ "string for example"を関数に渡すことができます。したがって、関数が失敗したときはいつでも、falseまたはnullをユーザーに出力して返します。ただ、MicrosoftがTryParseで何をするかのような..しかし、ここで我々としても失敗の理由を得ている:

public bool TrySomeFunction(out string errorMessage) 
{ 
    try 
    { 
     //code that may cause exception 

     return true;//operation completed successfully 
    } 
    catch (Exception exception) 
    { 
     errorMessage = exception.Message; 
    } 

    return false; 
} 
+0

私はこれを考える既存のTryパターンに適合し、停止例外なしで関数を呼び出すことができ、失敗の理由についての情報を返すように設計できるという点で、おそらく最良のアプローチです。 – Tekito

0

エラーの各方法に例外タイプを作成します。これらの例外タイプに基づいてユーザーメッセージを作成します。貴重なメッセージを完全に再現できるように、例外タイプにフィールドを追加することを恐れないでください。これは私が例外プログラミングで目にする最大の失敗です。

たとえば、ユーザーが入力しなかった必須フィールドがある場合はMissingRequiredFieldExceptionにはMissingFieldName(s)というプロパティがあります。こうすることで、スタックの上に、どのフィールドが欠落していたかについてユーザーに意味のあるメッセージを出力することができます。

このアプローチの最も重要な点は、ユーザーが読める文字列を生成する計算機能に依存していないことです。それは適切な場所で、より高いレベルで行われます。国際化が必要な場合はどうなりますか?ユーザーに基づいて言語を切り替える機能をリファクタリングするつもりですか?混乱の重大なケースのように聞こえる...ユーザ出力コードを扱う計算関数とは何ですか?

+0

申し訳ありませんが、関数がユーザーの出力テキストを生成するとは限りませんでした。私は、関数が何とか失敗の背後にある理由を与える必要があることを意味しました。元の質問を編集しました。 – Tekito

+0

@Tekito申し訳ありません。私はそのようなことがあなたの意図であることを示唆することを意味しませんでした。私は単に私の考えを伝えていただけで、なぜそれが良いものだと思ったのですか。 – jdmichal

0

私にとってこれは本当に例外処理について聞こえます。

独自の例外タイプを定義することができます.1つの条件が満たされた場合(またはそうでない場合)、別の場合には1つの例外をスローすることができます。

呼び出し側はNULLを返す

1

は大丈夫です...ユーザーに通知するか、そうでヌルと継続することができない方法の結果を設定し、したいと、スローされた例外の種類に応じて、何をすべきかを決定しますあなたの呼び出しコードがNULL値を扱う方法を知っていることが期待される場合。この例では、NULL(予期しない)値が関数内から返されるような時刻を記録しています。おそらく関数は、メッセージボックスを介してユーザーに通知することができます。それは本当にあなたが私が推測するすべての設定をどうやっているかにかかっています。

EDIT:

た後、私はコードが任意のUIクラスの外であることを見逃しているように見えたポストを再度読み込みます。コメントと同様に、ユーザーの表示メッセージは、他のコード内からではなく、表示するためにUIレイヤーに残す必要があります。したがって、メッセージを表示できるようにソートソートのフラグをUIに戻す必要があります。このインスタンスが関数のブレーカでない場合は、例外チェーンが問題にならないと言います。私は、これは、あなたがNULLの戻り値を持つ最初のインスタンスで行うように、各関数呼び出しの戻り値でそれを決定する必要があると思います - おそらく "警告"または何かのフラグを持つ戻り値のカスタムDataType

+1

私はこの最後のビットをお勧めしません。_おそらく、関数がメッセージボックス経由でユーザーに知らせることができます。 "_計算機能を表示すると、ユーザーのメッセージボックスが表示されます。関数は、1つのことと1つのことだけを実行する必要があります。 – jdmichal

+0

@jdmichal、関数がデザインクラスの外にあるのは確かにこれは良くありません。しかし、これが私がセットアップに依存しているという理由です。関数がある種の論理クラスにある場合(再読み込みの場合にそうであるように思われる)、警告を示すために何かを設計レベルに渡すことを望むでしょう(または何でも) – musefan

1

私は例外的な状況でを除いて、例外をスローしません。例外は投げるのに非常に高価です。言及されたmissingrequiredfield jdのような、本当に悪いもののためにそれらを保存してください。代わりに、私は、成功フラグ、nullable結果、および呼び出し側のルーチンがユーザーに表示できるメッセージのリストを持つオブジェクトを返します(または、ユーザーに表示するために次のレイヤーに戻す)

3

例外処理をフロー制御に使用しないでください。本当に例外的な状況に対してのみ例外をスローします。

... ahem。私の高い馬を降りる時間。

深刻なことに、私はあなたが解決しようとしている問題の性質を知らない。最初の質問は、あなたのアルゴリズムの失敗が本当に失敗したか、または評価できないことをNaNの値、つまり0で表すことができるかということです。それが本当に基本的な概念的な失敗であるならば、アルゴリズムは続行する前に入力をチェックすることができますか?その場合は、引数例外またはその派生クラス - 好ましくは後者をスローします。これは、他の消費コードが(IoCシナリオなどの)一般的なケースを処理でき、コードが特定のケースを処理できることを意味します。これについては、合理的に知ることができます。これを行うと、この機能を含むアセンブリにも、例外をスローする可能性のあるものを呼び出す前に、呼び出し側がインバウンド引数が有効であることを検証できる静的検証関数が用意されている必要があります。

+0

はい私は例外を止めるのを避けることができるので、機能を完全に呼び出す前に妥当性チェックを行うといいでしょう。そうすれば、私は、小切手に失敗の背後にある理由を返すことができます。 – Tekito

+0

結果を計算できない計算関数は例外的な状況です。しかし、私はこの場合、例外的な状況がユーザ入力を前に検証することによって回避できるように思われることに同意します。 – jdmichal

+0

@jdmichal:しかし、「失敗」はどういう意味ですか? 「関数はこれらのパラメータで定義されていません」と「これらのパラメータで計算しようとするには意味がありません」という概念的な違いがあります。未定義の領域は数学的に受け入れられ、代わりにNaNを返すのが適切かもしれません。 –

0

@Tomは、プログラムの流れを制御するために例外を投げてはならないことに同意します。あなたが考慮するかもしれないもう一つのアプローチは、(これは私の頭の上からである)デリゲートを渡している。

public static void Main() 
{ 
    Action<string> errorTarget = delegate(string s) { Console.WriteLine(s); }; 

    SomeFunction(errorTarget); 
} 

private static void SomeFunction(Action<string> errorTarget) 
{ 
    ... 
    // Send non-fatal errors to the errorTarget 
    if (result == null) 
    { 
     // Build the error message, then call errorTarget 
     errorTarget(errorMessage); 
    } 
    ... 
} 
1

あなたは一般的な結果クラスで必要な情報をラップすることができます。

public class MyClass 
{ 
    public static void Main() 
    { 
     var result = new MyClass().TrySomeFunction(); 

     if (result.Succeeded) 
     { 
      // use it 
      MyReturningResultType resultValue = result.GetResultValue(); 
     } 
     else 
     { 
      // use message 
      string message = result.ResultMessage; 
     } 

    } 

    Result<MyReturningResultType> TrySomeFunction() 
    { 
     try 
     { 
      MyReturningResultType value = CalculateIt(); 
      return new Result<MyReturningResultType>(value) { Succeeded = true }; 
     } 
     catch (Exception exception) 
     { 
      return new Result<MyReturningResultType>(default(MyReturningResultType)) 
      { 
       Succeeded = false, 
       ResultMessage = exception.Message 
      }; 
     } 
    } 
} 

public class Result<T> 
{ 
    public Result(T resultValue) { this.ResultValue = resultValue; } 
    public bool Succeeded { get; set; } 
    public string ResultMessage { get; set; } 
    public T GetResultValue() 
    { 
     if (ResultValue is T) 
     { 
      return (T)this.ResultValue; 
     } 

     return default(T); 
    } 

    private T ResultValue; 
} 
関連する問題