구문 분석 오류가 발생할 경우 자세한 정보를 제공하는 TryParse 메서드를 어떻게 디자인합니까?


9

사용자 입력을 구문 분석 할 때 일반적으로 예외를 throw하지 않고 확인 메소드를 사용하는 것이 좋습니다 . .NET BCL에서 이는 예를 들어 int.Parse(유효하지 않은 데이터에 대해 예외가 발생 함)과 int.TryParse( false유효하지 않은 데이터가 반환 됨)의 차이입니다.

나는 내 자신을 디자인하고 있습니다

Foo.TryParse(string s, out Foo result)

메서드와 반환 값이 확실하지 않습니다. 내가 사용할 수있는 bool.NET 자신과 같은 TryParse방법,하지만 그건에 대한 징후주지 않았 타입 정확한 이유에 대한 오류, s 로 해석 할 수 없었던을 Foo. (예를 들어, 일치하지 s않는 괄호, 문자 수가 잘못되었거나 또는 등이 Bar없는 문자 Baz등이있을 수 있음)

API 사용자 로서 작업 실패 이유를 알려주지 않고 성공 / 실패 부울을 반환하는 메소드를 싫어합니다 . 이로 인해 추측 게임을 디버깅 할 수 있으며 라이브러리의 클라이언트에도 적용하고 싶지 않습니다.

이 문제에 대한 많은 해결 방법 (상태 코드 반환, 오류 문자열 반환, 오류 문자열을 출력 매개 변수로 추가)을 생각할 수 있지만 모두 각각의 단점이 있으며 다음 규칙을 준수하고 싶습니다. .NET Framework .

따라서 내 질문은 다음과 같습니다.

.NET Framework에 (a) 예외를 발생시키지 않고 입력을 구문 분석하고 (b) 간단한 true / false 부울보다 더 자세한 오류 정보를 계속 반환하는 메서드가 있습니까?


1
그 링크는 예외를 던지고 잡는 것이 권장되지 않는다는 결론을 내리지 않습니다. 가장 좋은 방법은 사용하는 것 Parse()입니다.
paparazzo

답변:


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; }
}

Monad 버전은 다음과 같습니다.

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

자세한 구문 분석 오류 정보를 반환하는 .net 프레임 워크의 메소드를 알지 못합니다.


UI 레이어 바인딩에 대한 귀하의 의견을 이해하지만이 경우 Foo의 표준화 된 표준 문자열 표현이 있으므로 Foo.ToStringand 가 있어야 Foo.Parse합니다.
Heinzi

그리고 대담한 질문 으로이 패턴을 사용하는 .NET BCL의 예를 들어 주시겠습니까?
Heinzi

4
모나드는 어때요?
JacquesB

@Heinzi : a를 반환하는 모든 메소드는 필요한 정보에 Func<T>포함하면 해당 기준을 충족 T합니다. 자세한 오류 정보를 반환하는 것은 전적으로 귀하에게 달려 있습니다. Maybe<T>? 사용을 고려 했습니까 ? mikhail.io/2016/01/monads-clain-in-csharp
Robert Harvey

@JacquesB : 나는 같은 것을 궁금해했다. 메소드 서명은 모달 릭 동작과 호환되지만 그에 관한 것입니다.
Robert Harvey

1

MVC 프레임 워크 에서 ModelState 를 볼 수 있습니다. 일부 입력의 구문 분석 시도를 나타내며 오류 콜렉션이있을 수 있습니다.

즉, .net BCL에는 반복되는 패턴이 없다고 생각합니다. 예외는 .net의 오류 조건을보고하기위한 확립 된 패턴이기 때문입니다. 난 그냥 가서 예를 들어, 문제를 양복지 자신의 솔루션을 구현해야한다고 생각 ParseResult이 개 서브 클래스로 클래스를, 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.