เหตุผลในการแจ้งเตือนจะมีการอธิบายในส่วนThe issue with T?
ของ ลองประเภท Nullable อ้างอิง เรื่องสั้นสั้นถ้าคุณใช้T?
คุณต้องระบุว่าประเภทเป็นชั้นหรือ struct คุณสามารถสร้างสองประเภทสำหรับแต่ละกรณี
ปัญหาที่ลึกกว่าคือการใช้ประเภทหนึ่งเพื่อใช้ผลลัพธ์และถือทั้งค่าความสำเร็จและข้อผิดพลาดจะทำให้เกิดปัญหาเดียวกันผลลัพธ์ควรแก้ไขและอีกสองสามอย่าง
- ประเภทเดียวกันจะต้องมีค่าตายตัวไม่ว่าจะเป็นชนิดหรือข้อผิดพลาดหรือนำกลับเป็นค่าว่าง
- การจับคู่รูปแบบกับประเภทเป็นไปไม่ได้ คุณต้องใช้การจับคู่รูปแบบตำแหน่งแฟนซีเพื่อให้สิ่งนี้ทำงานได้
- เพื่อหลีกเลี่ยงการ nulls คุณจะต้องใช้สิ่งที่ต้องการตัวเลือก / อาจจะคล้ายกับ F # 's ตัวเลือก คุณยังคงไม่มี None รอบ ๆ ทั้งสำหรับค่าหรือข้อผิดพลาด
ผลลัพธ์ (และทั้งสองอย่าง) ใน F #
จุดเริ่มต้นควรเป็นประเภทผลลัพธ์ของ F #และสหภาพที่ถูกเลือกปฏิบัติ หลังจากทั้งหมดนี้ทำงานบน. NET
ประเภทผลลัพธ์ใน F # คือ:
type Result<'T,'TError> =
| Ok of ResultValue:'T
| Error of ErrorValue:'TError
ประเภทตัวเองเท่านั้นดำเนินการสิ่งที่พวกเขาต้องการ
DUs ใน F # อนุญาตให้จับคู่รูปแบบครบถ้วนสมบูรณ์โดยไม่ต้องใช้ค่า 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 ยังไม่มี DUs พวกเขามีกำหนดเวลาสำหรับ 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()
};
}
หากไม่มีการจับคู่รูปแบบครบถ้วนสมบูรณ์เราจะต้องเพิ่มส่วนเริ่มต้นนั้นเพื่อหลีกเลี่ยงคำเตือนของคอมไพเลอร์
ฉันยังคงมองหาวิธีที่จะได้รับการจับคู่ที่ละเอียดถี่ถ้วนโดยไม่แนะนำค่าตายถึงแม้ว่าพวกเขาจะเป็นเพียงตัวเลือก
ตัวเลือก / อาจจะ
การสร้างคลาส Option โดยวิธีที่ใช้การจับคู่แบบหมดจดนั้นง่ายกว่า:
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
};