开发者

iSynaptic.Commons and the Maybe Monad

开发者 https://www.devze.com 2023-04-10 11:16 出处:网络
I\'ve been trying to figure out how I could use the Maybe monad in iSynaptic.Commons in a context where my value retriever could throw an exception:

I've been trying to figure out how I could use the Maybe monad in iSynaptic.Commons in a context where my value retriever could throw an exception:

For example:

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>.NoV开发者_如何学JAVAalue;
if(maybe.HasValue) {
    //Do something
}

Is this possible with the implementation of maybe that is out there


There are several ways of using iSynaptic.Commons to allow an exception. Each way I found requires the .Catch() extension method to let the monad know to silently catch the exception. Also, be careful when accessing the property maybe.Value. If this property is Maybe.NoValue, an InvalidOperationException will be thrown.


1) Create a "OnExceptionNoValue" extension method. This will check the Maybe to see if it has an exception. If it does, a NoValue Maybe will be returned. Otherwise the original Maybe will be returned.

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) Create a "BindCatch" extension method. This changes the behavior of the normal bind when an exception is present to return Maybe.NoValue instead of throwing an exception.

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) This way also uses the Catch() extension method, but uses the maybe.HasValue property instead of relying on extension methods. If an exception is present in the Maybe, the HasValue property is false. When this value is false, the Maybe.NoValue can replace the value of the variable maybe or whatever needs to be done in this case.

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

These answers are all variations on the same theme, but I hope they are helpful.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号