解析エラーの場合に詳細情報を提供するTryParseメソッドをどのように設計しますか?


9

ユーザー入力を解析する場合、例外をスローしてキャッチするのではなく、検証メソッドを使用することをお勧めします。.NET BCLでは、これは、たとえばint.Parse(無効なデータで例外をスローする)とint.TryParsefalse無効なデータで戻る)の違いになります。

私は自分でデザインしています

Foo.TryParse(string s, out Foo result)

メソッドと私は戻り値がわからない。bool.NET独自のTryParseメソッドのように使用することもできますが、エラーのタイプ、つまりに解析できなかった正確な理由について sはわかりませんFoo。(たとえば、s括弧Barが一致していない、文字数が間違っている、対応するがないBazなど)

APIのユーザーとして、操作が失敗した理由を通知せずに成功/失敗のブール値を返すだけのメソッドは嫌いです。これにより、推測ゲームのデバッグが可能になり、ライブラリのクライアントにもそれを課したくありません。

私はこの問題の多くの回避策(ステータスコードを返す、エラー文字列を返す、エラーパラメータを出力パラメーターとして追加する)を考えることができますが、それぞれに欠点があり、また、 .NET Frameworkの

したがって、私の質問は次のとおりです。

(a)例外をスローせずに入力を解析し、(b)単純なtrue / falseブール値よりも詳細なエラー情報を返す.NET Frameworkのメソッドはありますか?


1
そのリンクは、例外をスローしてキャッチすることは推奨されないと結論付けていません。最良の方法は使用することParse()です。
パパラッツォ

回答:


5

戻り値の型にはモナドパターンを使用することをお勧めします。

ParseResult<Foo> foo = FooParser.Parse("input");

また、ドメインレイヤーをUIレイヤーに直接バインドし、単一責任の原則にも違反するため、ユーザー入力からどのように解析する必要があるかを判断するのはFooの責任ではありません。

Fooユースケースに応じて、ジェネリックを使用する代わりに、固有の解析結果クラスを作成することもできます。

foo固有の解析結果クラスは次のようになります。

class FooParseResult
{
     Foo Value { get; set; }
     bool PassedRequirement1 { get; set; }
     bool PassedRequirement2 { get; set; }
}

これはモナド版です:

class ParseResult<T>
{
     T Value { get; set; }
     string ParseErrorMessage { get; set; }
     bool WasSuccessful { get; set; }
}

詳細な解析エラー情報を返す.netフレームワークのメソッドについては知りません。


私は、UI層が結合についてコメントを理解し、それが持っていることは理にかなっていますので、この場合には、Fooのの標準化、標準的な文字列表現が存在するFoo.ToStringFoo.Parse
ハインツィ

そして、私の太字の質問について、このパターンを使用する.NET BCLの例を教えてもらえますか?
ハインツィ

4
そのモナドはどうですか?
JacquesB 2018年

@Heinzi:必要な情報にFunc<T>含めた場合、aを返すメソッドはその基準を満たしTます。詳細なエラー情報を返すのは主にあなた次第です。Maybe<T>?の使用を検討しましたか?mikhail.io/2016/01/monads-explained-in-csharpを
Robert Harvey

@JacquesB:私はちょっと同じことを考えていました。メソッドのシグネチャは、動的な動作と互換性がありますが、それだけです。
ロバートハーベイ

1

MVCフレームワークでModelStateを確認できます。これは、一部の入力の試行された解析を表し、エラーのコレクションがある場合があります。

とは言っても、例外は.netのエラー状態を報告するための確立されたパターンであるため、.net BCLにはこのパターンが繰り返し発生することはないと思います。私は先に進んで、問題に合った独自のソリューションを実装する必要があると思います。たとえば、ParseResult2つのサブクラスを持つクラス、SuccessfulParseおよびFailedParseにはSuccessfulParse、解析された値をFailedParse持つプロパティがあり、エラーメッセージプロパティがあります。これをC#7のパターンマッチングと組み合わせると、かなりエレガントになる可能性があります。


1

どのようにしてなぜ失敗したのかTryParse/Convert/etc.時々知る必要がある方法を使用したいという同様の問題に遭遇しました。

一部のシリアライザーがエラーを処理し、イベントを使用する方法からインスピレーションを得ました。このように、私のTryX(..., out T)メソッドの構文は他のメソッドと同じようにきれいに見えfalse、パターンが意味するように単純に確実に返します。

ただし、詳細が必要な場合は、イベントハンドラーを追加するだけで、パッケージに必要な結果を必要なだけ複雑または単純に取得できます(MyEventArgs以下)。文字列のリストに追加し、ExceptionDispatchInfo例外を追加してキャプチャします。呼び出し側に、問題が発生した場合の対処方法を決定させます。

public class Program
{
    public static void Main()
    {
        var c = new MyConverter();

        //here's where I'm subscibing to errors that occur
        c.Error += (sender, args) => Console.WriteLine(args.Details);

        c.TryCast<int>("5", out int i);
    }
}

//here's our converter class
public class MyConverter
{
    //invoke this event whenever something goes wrong and fill out your EventArgs with details
    public event EventHandler<MyEventArgs> Error;

    //intentionally stupid implementation
    public bool TryCast<T>(object input, out T output)
    {
        bool success = true;
        output = default (T);

        //try-catch here because it's an easy way to demonstrate my example
        try
        {
            output = (T)input;
        }
        catch (Exception ex)
        {
            success = false;
            Error?.Invoke(this, new MyEventArgs{Details = ex.ToString()});
        }

        return success;
    }
}

//stores whatever information you want to make available
public class MyEventArgs : EventArgs
{
    public string Details {get; set;}
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.