异常或者是C#中的一个monad

前端之家收集整理的这篇文章主要介绍了异常或者是C#中的一个monad前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在努力初步了解单子.

我有一个数据层调用,其结果我想要返回一个结果,例如没有行更新/数据集等,或异常.我想我需要使用我可以看到的异常单子,作为一个单体的特殊情况

我已经看了各种各样的样本 – 吨的Maybe样本,我不太确定如何或如果推广这个成为一个单体 – 但我找不到哪些不在haskell – 不幸的是,我最肯定不要grok haskell!

我想知道有没有人可以指点我的样品.

解决方法

在C#中学习一点关于monads的同时,为了练习,我为自己实现了一个特殊的monad.有了这个monad,你可以链接可能会抛出异常的操作,就像这两个例子一样:
  1. var exc1 = from x in 0.ToExceptional()
  2. from y in Exceptional.Execute(() => 6 / x)
  3. from z in 7.ToExceptional()
  4. select x + y + z;
  5. Console.WriteLine("Exceptional Result 1: " + exc1);
  6.  
  7. var exc2 = Exceptional.From(0)
  8. .ThenExecute(x => x + 6 / x)
  9. .ThenExecute(y => y + 7);
  10. Console.WriteLine("Exceptional Result 2: " + exc2);

两个表达式产生相同的结果,只是语法不同.结果将是一个特殊的< T>与出现的DivideByZeroException设置为属性.第一个例子显示了使用LINQ的monad的“核心”,第二个例子包含一个不同的,也许更可读的语法,它以更容易理解的方式说明了方法链接.

那么它是如何实现的呢?这里是超凡的< T>类型:

  1. public class Exceptional<T>
  2. {
  3. public bool HasException { get; private set; }
  4. public Exception Exception { get; private set; }
  5. public T Value { get; private set; }
  6.  
  7. public Exceptional(T value)
  8. {
  9. HasException = false;
  10. Value = value;
  11. }
  12.  
  13. public Exceptional(Exception exception)
  14. {
  15. HasException = true;
  16. Exception = exception;
  17. }
  18.  
  19. public Exceptional(Func<T> getValue)
  20. {
  21. try
  22. {
  23. Value = getValue();
  24. HasException = false;
  25. }
  26. catch (Exception exc)
  27. {
  28. Exception = exc;
  29. HasException = true;
  30. }
  31. }
  32.  
  33. public override string ToString()
  34. {
  35. return (this.HasException ? Exception.GetType().Name : ((Value != null) ? Value.ToString() : "null"));
  36. }
  37. }

Monad通过扩展方法ToExceptional< T>()和SelectMany< T,U>()完成,对应于monad的Unit和Bind函数

  1. public static class ExceptionalMonadExtensions
  2. {
  3. public static Exceptional<T> ToExceptional<T>(this T value)
  4. {
  5. return new Exceptional<T>(value);
  6. }
  7.  
  8. public static Exceptional<T> ToExceptional<T>(this Func<T> getValue)
  9. {
  10. return new Exceptional<T>(getValue);
  11. }
  12.  
  13. public static Exceptional<U> SelectMany<T,U>(this Exceptional<T> value,Func<T,Exceptional<U>> k)
  14. {
  15. return (value.HasException)
  16. ? new Exceptional<U>(value.Exception)
  17. : k(value.Value);
  18. }
  19.  
  20. public static Exceptional<V> SelectMany<T,U,V>(this Exceptional<T> value,Exceptional<U>> k,V> m)
  21. {
  22. return value.SelectMany(t => k(t).SelectMany(u => m(t,u).ToExceptional()));
  23. }
  24. }

还有一些小帮手,不是monad的核心部分:

  1. public static class Exceptional
  2. {
  3. public static Exceptional<T> From<T>(T value)
  4. {
  5. return value.ToExceptional();
  6. }
  7.  
  8. public static Exceptional<T> Execute<T>(Func<T> getValue)
  9. {
  10. return getValue.ToExceptional();
  11. }
  12. }
  13.  
  14. public static class ExceptionalExtensions
  15. {
  16. public static Exceptional<U> ThenExecute<T,U> getValue)
  17. {
  18. return value.SelectMany(x => Exceptional.Execute(() => getValue(x)));
  19. }
  20. }

一些解释:只要链中的一种方法抛出异常,就会执行一个使用这个monad构建的方法链.在这种情况下,不再执行链的更多方法,并且将返回第一个抛出的异常作为异常< T>的一部分.结果.在这种情况下,将会设置HasException和Exception属性.如果没有发生异常,则HasException将为false,并且将设置Value属性,其中包含执行的方法链的结果.

请注意,异常< T>(Func< T> getValue)构造器负责异常处理,并且SelectMany< T,U>()方法负责区分以前执行的方法是否引发了异常.

猜你在找的C#相关文章