Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a .NET equivalent of Scala's Try?

Tags:

c#

.net

scala

I have been taking part in the Coursera reactive programming course and noticed the parallels between

  1. .NET Tasks and Scala Futures
  2. Observables are obviously very similar
  3. .NET IEnumerable and Scala Iterable

In the course Erik Meijer draws a table similar to this

           Sync     | Async
Single   | Try      | Future
Multiple | Iterable | Observable

While the rest have equivalent or similar constructs in .NET I couldn't find anything like try. Does something similar exist?

like image 961
Jim Jeffries Avatar asked Sep 06 '25 12:09

Jim Jeffries


2 Answers

There's nothing built in, so you'd have to write your own. Based on the Scala Try I would make something like:

public interface ITry<T> : IEnumerable<T>
{
    T Value { get; }
    ITry<U> SelectMany<U>(Func<T, ITry<U>> bindFunc);
    bool IsSuccess { get; }
}

public class FailedTry<T> : ITry<T>
{
    private readonly Exception ex;
    public FailedTry(Exception ex)
    {
        this.ex = ex;
    }

    public T Value
    {
        get { throw new InvalidOperationException("Can't get value for failed Try"); }
    }

    public ITry<U> SelectMany<U>(Func<T, ITry<U>> bindFunc)
    {
        return new FailedTry<U>(this.ex);
    }

    public bool IsSuccess
    {
        get { return false; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        yield break;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

public class SuccessTry<T> : ITry<T>
{
    public SuccessTry(T value)
    {
        this.Value = value;
    }

    public T Value { get; private set; }

    public ITry<U> SelectMany<U>(Func<T, ITry<U>> bindFunc)
    {
        if (bindFunc == null) return new FailedTry<U>(new ArgumentNullException("bindFunc"));
        try
        {
            return bindFunc(this.Value);
        }
        catch (Exception ex)
        {
            return new FailedTry<U>(ex);
        }
    }

    public bool IsSuccess
    {
        get { return true; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        yield return this.Value;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

public static class Try
{
    public static ITry<T> Failed<T>(Exception ex)
    {
        return new FailedTry<T>(ex);
    }

    public static ITry<T> Create<T>(Func<T> create)
    {
        if (create == null) return new FailedTry<T>(new ArgumentNullException("create"));
        try
        {
            return new SuccessTry<T>(create());
        }
        catch (Exception ex)
        {
            return new FailedTry<T>(ex);
        }
    }

    public static ITry<U> Select<T, U>(this ITry<T> @try, Func<T, U> mapFunc)
    {
        return @try.SelectMany(v => Create(() => mapFunc(v)));
    }
}
like image 93
Lee Avatar answered Sep 08 '25 19:09

Lee


Is it something like this?

public class Try<TResult>
{
    private readonly bool failure;
    private readonly TResult result;
    private readonly Exception exception;

    protected Try(TResult result)
    {
        this.result = result;
    }

    protected Try(Exception ex)
    {
        this.exception = ex;
        this.failure = true;
    }

    public TResult Result
    {
        get
        {
            if (this.failure) throw new InvalidOperationException();
            return this.result;
        }
    }

    public Exception Exception
    {
        get
        {
            if (!this.failure) throw new InvalidOperationException();
            this.exception;
        }
    }

    public bool Failure
    {
        get
        {
            return this.failure;
        }
    }

    public static Try<TResult> Invoke(Func<TResult> func)
    {
        TResult result;
        try
        {
            result = func();
            return new Try(result);
        }
        catch (Exception ex)
        {
            return new Try(ex);
        }
    }

    public static IEnumerable<Try<TResult>> Invoke(
            IEnumerable<Func<TResult>> funcs)
    {
        return funcs.Select(Invoke);
    }
}

You'd obviously have to overload Invoke to accept the range of typed delegates that you desire.

like image 41
Jodrell Avatar answered Sep 08 '25 19:09

Jodrell