Như đã lưu ý, bạn gần như đã triển khai một Monad tại đây.
Mã của bạn hơi không thích hợp trong đó các lambdas có tác dụng phụ. Monads giải quyết điều này một cách tao nhã hơn.
Vì vậy, tại sao không biến mã của bạn thành một Monad phù hợp?
Phần thưởng: bạn có thể sử dụng cú pháp LINQ!
tôi trình bày:
LINQ to Kết quả
Ví dụ:
var result =
from a in SomeThingHappensHere()
let someData = a.Data
from b in SomeOtherThingHappensHere(someData)
from c in AndYetAnotherThing()
from d in AndOneMoreThing(someData)
select d;
HandleTheFinalResultHere(result.Value);
Với LINQ to Kết quả, điều này đầu tiên thực hiện SomeThingHappensHere
. Nếu thành công, nó sẽ nhận được giá trị của thuộc tính Data
của kết quả và thực hiện SomeOtherThingHappensHere
.Nếu thành công, nó thực hiện AndYetAnotherThing
, v.v.
Như bạn có thể thấy, bạn có thể dễ dàng chuỗi hoạt động và tham khảo kết quả của các hoạt động trước đó. Mỗi hoạt động sẽ được thực hiện cái khác, và thực hiện sẽ dừng lại khi gặp lỗi.
Các bit from x in
mỗi dòng là một chút ồn ào, nhưng IMO không có gì phức tạp so sánh sẽ nhận được dễ đọc hơn này!
Làm cách nào để chúng tôi thực hiện công việc này?
Monads trong C# bao gồm ba phần:
một loại Something-of-T,
Select
/SelectMany
phương pháp khuyến nông cho nó, và
một để chuyển đổi một số T thành một số Cái gì đó của T.
Tất cả những gì bạn cần làm là tạo ra thứ gì đó giống như Monad, cảm giác như Monad và có mùi giống Monad và mọi thứ sẽ hoạt động tự động.
Các loại và phương pháp cho LINQ cho kết quả như sau.
quả <T> loại:
Một lớp đơn giản mà đại diện cho một kết quả. Kết quả là giá trị loại T hoặc lỗi. Kết quả có thể được tạo từ T hoặc từ Ngoại lệ.
class Result<T>
{
private readonly Exception error;
private readonly T value;
public Result(Exception error)
{
if (error == null) throw new ArgumentNullException("error");
this.error = error;
}
public Result(T value) { this.value = value; }
public Exception Error
{
get { return this.error; }
}
public bool IsError
{
get { return this.error != null; }
}
public T Value
{
get
{
if (this.error != null) throw this.error;
return this.value;
}
}
}
phương pháp mở rộng:
Triển khai cho Select
và SelectMany
phương pháp. Chữ ký của phương thức được đưa ra trong thông số C#, vì vậy tất cả những gì bạn phải lo lắng là việc triển khai chúng. Những điều này khá tự nhiên nếu bạn cố gắng kết hợp tất cả các đối số phương thức một cách có ý nghĩa.
static class ResultExtensions
{
public static Result<TResult> Select<TSource, TResult>(this Result<TSource> source, Func<TSource, TResult> selector)
{
if (source.IsError) return new Result<TResult>(source.Error);
return new Result<TResult>(selector(source.Value));
}
public static Result<TResult> SelectMany<TSource, TResult>(this Result<TSource> source, Func<TSource, Result<TResult>> selector)
{
if (source.IsError) return new Result<TResult>(source.Error);
return selector(source.Value);
}
public static Result<TResult> SelectMany<TSource, TIntermediate, TResult>(this Result<TSource> source, Func<TSource, Result<TIntermediate>> intermediateSelector, Func<TSource, TIntermediate, TResult> resultSelector)
{
if (source.IsError) return new Result<TResult>(source.Error);
var intermediate = intermediateSelector(source.Value);
if (intermediate.IsError) return new Result<TResult>(intermediate.Error);
return new Result<TResult>(resultSelector(source.Value, intermediate.Value));
}
}
Bạn có thể tự do thay đổi kết quả <T> lớp và các phương pháp khuyến nông, ví dụ, để thực hiện các quy định phức tạp hơn. Chỉ chữ ký của các phương thức mở rộng phải chính xác như đã nêu.
Nó không phải là rất dễ dàng để đọc .... –
100% đồng ý. thật đáng buồn, nó vẫn là một cải tiến đáng kể so với những gì tôi bắt đầu. một ít định dạng hơn có thể giúp ... có thể ... –
Ouch, mắt tôi .... –