Uyarı sebebi bölümünde açıklanmıştır The issue with T?
arasında null Referans türlerini deneyin . Uzun lafın kısası, eğer kullanıyorsanız T?
, türün bir sınıf mı yoksa yapı mı olduğunu belirtmeniz gerekir. Her durum için iki tür oluşturabilirsiniz.
Daha derin bir sorun, Sonuç uygulamak ve Başarı ve Hata değerlerini tutmak için bir tür kullanmanın, aynı sorunları geri getirmesi ve sonucun düzeltmesi gerekiyordu.
- Aynı tür, tür veya hata etrafında ölü bir değer taşımak veya null'ları geri getirmek zorundadır
- Tür üzerinde desen eşleşmesi mümkün değildir. Bunun işe yaraması için bazı süslü konumsal desen eşleştirme ifadeleri kullanmanız gerekir.
- Boş değerlerden kaçınmak için, F # Seçeneklerine benzer şekilde Option / Belki gibi bir şey kullanmanız gerekir . Yine de değer ya da hata için bir Yok taşırsınız.
F # dilinde sonuç (ve her ikisi de)
Başlangıç noktası F # 'ın Sonuç tipi ve ayrımcı sendikalar olmalıdır. Sonuçta, bu zaten .NET üzerinde çalışıyor.
F # içindeki bir sonuç türü:
type Result<'T,'TError> =
| Ok of ResultValue:'T
| Error of ErrorValue:'TError
Türlerin kendileri sadece ihtiyaç duyduklarını taşırlar.
F # 'deki DU'lar, boş değer gerektirmeden kapsamlı desen eşleşmesine izin verir:
match res2 with
| Ok req -> printfn "My request was valid! Name: %s Email %s" req.Name req.Email
| Error e -> printfn "Error: %s" e
Bunu C # 8'de taklit etmek
Ne yazık ki, C # 8'in henüz DU'ları yok, C # 9 için planlanıyorlar. C # 8'de bunu taklit edebiliriz, ancak kapsamlı eşleşmeyi kaybediyoruz:
#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;
}
Ve kullanın:
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()
};
}
Kapsamlı desen eşleşmesi olmadan, derleyici uyarılarını önlemek için bu varsayılan maddeyi eklememiz gerekir.
Hala ayrıntılı eşleştirme almak için bir yol arıyorum olmadan sadece bir seçenek olsa bile, ölü değerleri tanıtarak.
Opsiyon / Belki
Kapsamlı eşleme kullanan bir Option sınıfı oluşturmak daha basittir:
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;
}
Hangi ile kullanılabilir:
string cateGory = someValue switch { Option<Category> (_ ,false) =>"No Category",
Option<Category> (var v,true) => v.Name
};