异常或任单子在C# [英] Exception or Either monad in C#

查看:94
本文介绍了异常或任单子在C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用神交拿到单子有了初步的了解。

I am trying to grok get a preliminary understanding of monads.

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

I have a data layer call whose result I would like to return monadically either as a result eg no of rows updated/dataset etc, or an exception. I figure I need to use the Exception monad which I could see as a special case of the Either monad

我回头望望各种样品 - 也许样本吨,而且我不太清楚如何,或者如果它推广成为一个单子要么 - 但我无法找到任何不属于在Haskell - ,不幸的是,我肯定不神交哈斯克尔

I've looked round at various samples - tonnes of Maybe samples, and I am not quite sure how or if to generalise this to become an Either monad - but I can't find any which are not in haskell - and, unfortunately, I most certainly don't grok haskell!

我想知道如果任何人都可以点我到任何样本。

I was wondering if anyone could point me to any samples.

推荐答案

虽然学习了一下关于C#单子,锻炼我实现了一个特殊单子自己。有了这个单子,你可以链接起来的操作可能抛出例外就像在这2个例子:

While learning a bit about monads in C#, for exercise I implemented an Exceptional monad for myself. With this monad, you can chain up operations that might throw an Exception like in these 2 examples:

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单子的核心,第二个包含不同的或许更可读的语法,这说明该方法更易于理解的方式链接。

Both expressions yield the same result, just the syntax is different. The result will be an Exceptional<T> with the arisen DivideByZeroException set as property. The first example shows the "core" of the monad using LINQ, the second contains a different and perhaps more readable syntax, which illustrates the method chaining in a more understandable way.

那么,它是如何实现的?这里的卓越< T> 键入:

So, how it's implemented? Here's the Exceptional<T> type:

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"));
    }
}



单子是通过扩展方法<$ C $完成C> ToExceptional< T>()和的SelectMany< T,U>(),对应于单子的单位和绑定功能:

The monad is completed through extension methods ToExceptional<T>() and SelectMany<T, U>(), that correspond to the monad's Unit and Bind functions:

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, Func<T, Exceptional<U>> k, Func<T, U, V> m)
    {
        return value.SelectMany(t => k(t).SelectMany(u => m(t, u).ToExceptional()));
    }
}

和一些小帮手结构,不属于的一部分单子的核心:

And some little helper structures, that are not part of the monad's core:

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>(this Exceptional<T> value, Func<T, U> getValue)
    {
        return value.SelectMany(x => Exceptional.Execute(() => getValue(x)));
    }
}



一些解释:这个单子建立了一个方法链只要链的一个方法抛出一个异常执行。在这种情况下,没有更多的链的方法将被执行,第一个抛出的异常将返回为卓越<的一部分; T> 的结果。在这种情况下, HasException 例外属性将被设置。如果没有例外时, HasException 属性将被设置,包含执行的方法链的结果。

Some explanation: a method chain built with this monad is executed as long as one method of the chain throws an exception. In this case no more method of the chain will be executed and the first thrown exception will be returned as part of an Exceptional<T> result. In this case the HasException and Exception properties will be set. If no Exception occurs, HasException will be false and the Value property will be set, containing the result of the executed method chain.

请注意,卓越< T>(Func键< T>的getValue)的构造函数,负责异常处理和的SelectMany< T,U>()方法负责,如果一个方法,即在执行前,已抛出异常区别。

Note that the Exceptional<T>(Func<T> getValue) constructor is responsible for the exception handling and the SelectMany<T,U>() method is responsible for distinguishing if a method, that was executed before, has thrown an exception.

这篇关于异常或任单子在C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆