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

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

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

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

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

解决方法

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

var exc2 = Exceptional.From(0)
           .ThenExecute(x => x + 6 / x)
           .ThenExecute(y => y + 7);
Console.WriteLine("Exceptional Result 2: " + exc2);

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

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

public class Exceptional<T>
{
    public bool HasException { get; private set; }
    public Exception Exception { get; private set; }
    public T Value { get; private set; }

    public Exceptional(T value)
    {
        HasException = false;
        Value = value;
    }

    public Exceptional(Exception exception)
    {
        HasException = true;
        Exception = exception;
    }

    public Exceptional(Func<T> getValue)
    {
        try
        {
            Value = getValue();
            HasException = false;
        }
        catch (Exception exc)
        {
            Exception = exc;
            HasException = true;
        }
    }

    public override string ToString()
    {
        return (this.HasException ? Exception.GetType().Name : ((Value != null) ? Value.ToString() : "null"));
    }
}

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

public static class ExceptionalMonadExtensions
{
    public static Exceptional<T> ToExceptional<T>(this T value)
    {
        return new Exceptional<T>(value);
    }

    public static Exceptional<T> ToExceptional<T>(this Func<T> getValue)
    {
        return new Exceptional<T>(getValue);
    }

    public static Exceptional<U> SelectMany<T,U>(this Exceptional<T> value,Func<T,Exceptional<U>> k)
    {
        return (value.HasException)
            ? new Exceptional<U>(value.Exception)
            : k(value.Value);
    }

    public static Exceptional<V> SelectMany<T,U,V>(this Exceptional<T> value,Exceptional<U>> k,V> m)
    {
        return value.SelectMany(t => k(t).SelectMany(u => m(t,u).ToExceptional()));
    }
}

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

public static class Exceptional
{
    public static Exceptional<T> From<T>(T value)
    {
        return value.ToExceptional();
    }

    public static Exceptional<T> Execute<T>(Func<T> getValue)
    {
        return getValue.ToExceptional();
    }
}

public static class ExceptionalExtensions
{
    public static Exceptional<U> ThenExecute<T,U> getValue)
    {
        return value.SelectMany(x => Exceptional.Execute(() => getValue(x)));
    }
}

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

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

猜你在找的C#相关文章