4

我一直在试图弄清楚如何在我的值检索器可能引发异常的上下文中使用iSynaptic.Commons中的 Maybe monad:

例如:

dynamic expando = new Expando();
expando.Name = "John Doe";

var maybe = Maybe.Defer(()=>(string)expando.NonExistingProperty);

//In this context I would like the exception which is thrown 
//to result in Maybe<string>.NoValue;
if(maybe.HasValue) {
    //Do something
}

这可能与可能存在的实施

4

1 回答 1

2

有几种方法可以使用 iSynaptic.Commons 来允许异常。我发现的每种方式都需要 .Catch() 扩展方法来让 monad 知道静默捕获异常。另外,访问属性maybe.Value时要小心。如果此属性为 Maybe.NoValue,则会抛出 InvalidOperationException。


1) 创建一个“OnExceptionNoValue”扩展方法。这将检查 Maybe 以查看它是否有异常。如果是这样,将返回一个 NoValue Maybe。否则原始的 Maybe 将被退回。

public static class MaybeLocalExtensions
{
    public static Maybe<T> OnExceptionNoValue<T>(this Maybe<T> maybe)
    {
        return maybe.Exception != null ? Maybe<T>.NoValue : maybe;
    }
}

// Sample Use Case:
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch()
    .OnExceptionNoValue();

2) 创建一个“BindCatch”扩展方法。当存在异常以返回 Maybe.NoValue 而不是抛出异常时,这会更改正常绑定的行为。

public static class MaybeLocalExtensions
{
    public static Maybe<TResult> BindCatch<T, TResult>(this Maybe<T> @this, Func<T, Maybe<TResult>> selector)
    {
        var self = @this;

        return new Maybe<TResult>(() => {
            if (self.Exception != null)
                return Maybe<TResult>.NoValue;

            return self.HasValue ? selector(self.Value) : Maybe<TResult>.NoValue;
        });
    }
}

// Sample Use Case:
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch()
    .BindCatch(m => m.ToMaybe());

3)这种方式也使用了Catch()扩展方法,但是使用了maybe.HasValue属性,而不是依赖扩展方法。如果 Maybe 中存在异常,则 HasValue 属性为 false。当此值为 false 时,Maybe.NoValue 可以替换变量的值可能或在这种情况下需要做的任何事情。

dynamic expando = new ExpandoObject();
expando.Name = "John Doe";

// This example falls to the else block.
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch();

//In this context I would like the exception which is thrown 
//to result in Maybe<string>.NoValue;
if (maybe.HasValue) {
    //Do something
    Console.WriteLine(maybe.Value);
} else {
    maybe = Maybe<string>.NoValue; // This line is run
}

// This example uses the if block.
maybe = Maybe.Defer(() => (string)expando.Name).Catch();
//to result in Maybe<string>.NoValue;
if (maybe.HasValue) {
    //Do something
    Console.WriteLine(maybe.Value); //This line is run
} else {
    maybe = Maybe<string>.NoValue;
}

这些答案都是同一主题的变体,但我希望它们有所帮助。

于 2011-10-04T22:05:36.683 回答