경고의 이유는 널 입력 가능 참조 유형 시도 섹션 The issue with T?
에 설명되어 있습니다. 당신이 사용한다면 긴 이야기 짧게T?
사용하는 경우 유형이 클래스인지 구조 체인지 지정해야합니다. 각 사례마다 두 가지 유형을 만들 수 있습니다.
더 큰 문제는 한 가지 유형을 사용하여 결과를 구현하고 성공 및 오류 값을 모두 보유하면 결과가 해결해야하는 것과 동일한 문제가 발생한다는 것입니다.
- 동일한 유형은 유형 또는 오류의 데드 값을 가져 오거나 널을 가져와야합니다.
- 유형의 패턴 일치가 불가능합니다. 이 기능을 사용하려면 멋진 위치 패턴 일치 표현식을 사용해야합니다.
- null을 피하려면 F #의 Options 와 비슷한 Option / Maybe와 같은 것을 사용해야합니다 . 그래도 값이나 오류에 대해 None을 가지고 다닐 것입니다.
F #의 결과 (및 둘 중 하나)
시작점은 F #의 결과 유형 과 차별적 노조 여야합니다 . 결국 이것은 이미 .NET에서 작동합니다.
F #의 결과 유형은 다음과 같습니다.
type Result<'T,'TError> =
| Ok of ResultValue:'T
| Error of ErrorValue:'TError
유형 자체는 필요한 것을 운반합니다.
F #의 DU는 null없이 전체 패턴 일치를 허용합니다.
match res2 with
| Ok req -> printfn "My request was valid! Name: %s Email %s" req.Name req.Email
| Error e -> printfn "Error: %s" e
C # 8에서 이것을 에뮬레이션
불행히도 C # 8에는 아직 DU가 없으며 C # 9로 예정되어 있습니다. C # 8에서는 이것을 에뮬레이트 할 수 있지만 철저한 일치를 잃습니다.
#nullable enable
public interface IResult<TResult,TError>{}
struct Success<TResult,TError> : IResult<TResult,TError>
{
public TResult Value {get;}
public Success(TResult value)=>Value=value;
public void Deconstruct(out TResult value)=>value=Value;
}
struct Error<TResult,TError> : IResult<TResult,TError>
{
public TError ErrorValue {get;}
public Error(TError error)=>ErrorValue=error;
public void Deconstruct(out TError error)=>error=ErrorValue;
}
그리고 그것을 사용하십시오 :
IResult<double,string> Sqrt(IResult<double,string> input)
{
return input switch {
Error<double,string> e => e,
Success<double,string> (var v) when v<0 => new Error<double,string>("Negative"),
Success<double,string> (var v) => new Success<double,string>(Math.Sqrt(v)),
_ => throw new ArgumentException()
};
}
철저한 패턴 일치가 없으면 컴파일러 경고를 피하기 위해 해당 기본 절을 추가해야합니다.
나는 단지 옵션 일지라도 죽은 값 을 도입 하지 않고 철저한 일치를 얻는 방법을 찾고 있습니다.
옵션 / 아마
철저한 일치를 사용하는 방법으로 옵션 클래스를 만드는 것이 더 간단합니다.
readonly struct Option<T>
{
public readonly T Value {get;}
public readonly bool IsSome {get;}
public readonly bool IsNone =>!IsSome;
public Option(T value)=>(Value,IsSome)=(value,true);
public void Deconstruct(out T value,out bool isSome)=>(value,isSome)=(Value,IsSome);
}
//Convenience methods, similar to F#'s Option module
static class Option
{
public static Option<T> Some<T>(T value)=>new Option<T>(value);
public static Option<T> None<T>()=>default;
}
다음과 함께 사용할 수 있습니다 :
string cateGory = someValue switch { Option<Category> (_ ,false) =>"No Category",
Option<Category> (var v,true) => v.Name
};