如果匹配则返回C#返回值,否则继续

时间:2020-01-25 22:18:58

标签: c#

这可能是不可能的,但是我心中的强迫症至少要问是否有办法:)

我有这种方法:

public async Task<List<Strategy>> Handle(StrategyList query, CancellationToken cancellationToken)
{
    return _attemptHandler.List();
}

我现在添加了一些尝试以帮助处理错误,因此我的代码更改为:

public async Task<Attempt<List<Strategy>>> Handle(StrategyList query, CancellationToken cancellationToken)
{
    var attempt = _attemptHandler.List();
    if (attempt.Failed) return attempt.Error;

    return attempt.Result.ToList();
}

Attempt这样的IdentityResult。 我想做的是,完全删除第二行,这样它就变成了这样:

public async Task<Attempt<List<Strategy>>> Handle(StrategyList query, CancellationToken cancellationToken)
{
    var attempt = _attemptHandler.List().ThrowIfError();

    return attempt.Result.ToList();
}

因此,基本上,如果尝试获取列表时出错,则返回该错误(在方法ThrowIfError中),但如果没有,请继续进行return attempt.Result.ToList()

这可能吗?

您可能会问为什么。我在此给出的用例看起来并不多,但在某些地方我必须检查多次尝试,我希望它能做到而不必一​​遍又一遍地编写相同的代码(即{ 1}})


以下是多次尝试的示例:

if (attempt.Failed) return attempt.Error;

2 个答案:

答案 0 :(得分:1)

这里是:

  1. Attempt<TResult>类的简单实现,使您可以完成想要实现的目标和
  2. 一个演示如何使用它的单元测试。

为简化起见,该示例使用List<string>作为结果类型。 HandleAsync方法与您的Handle方法相对应。 MakeAttemptAsync()与您的attemptHandler.List()相当。

    /// <summary>
    /// Utility class that helps shorten the calling code.
    /// </summary>
    public static class Attempt
    {
        public static async Task<Attempt<TResult>> ResultAsync<TResult>(Task<TResult> task)
        {
            return await Attempt<TResult>.ResultAsync(task);
        }

        public static Attempt<TResult> ResultOf<TResult>(Func<TResult> func)
        {
            return Attempt<TResult>.ResultOf(func);
        }
    }

    /// <summary>
    /// Represents a successful or failed attempt.
    /// </summary>
    /// <typeparam name="TResult">The result type.</typeparam>
    public class Attempt<TResult>
    {
        private Attempt(TResult result, bool success, Exception exception)
        {
            Result = result;
            Success = success;
            Exception = exception;
        }

        public TResult Result { get; }

        public bool Success { get; }

        public Exception Exception { get; }

        public static async Task<Attempt<TResult>> ResultAsync(Task<TResult> task)
        {
            try
            {
                TResult result = await task;
                return new Attempt<TResult>(result, true, null);
            }
            catch (Exception ex)
            {
                return new Attempt<TResult>(default, false, ex);
            }
        }

        public static Attempt<TResult> ResultOf(Func<TResult> func)
        {
            try
            {
                TResult result = func();
                return new Attempt<TResult>(result, true, null);
            }
            catch (Exception ex)
            {
                return new Attempt<TResult>(default, false, ex);
            }
        }
    }

    public class AttemptsTests
    {
        private static readonly List<string> SuccessList = new List<string> { "a", "b", "c" };

        /// <summary>
        /// Simple demonstrator for a short, synchronous handler making use of the
        /// Attempt class, called with flag equal to true or false to simulate
        /// success or failure of the MakeAttemptAsync method.
        /// </summary>
        private static Attempt<List<string>> Handle(bool flag)
        {
            return Attempt.ResultOf(() => MakeAttempt(flag));
        }

        /// <summary>
        /// Simple demonstrator for a short, asynchronous handler making use of the
        /// Attempt class, called with flag equal to true or false to simulate
        /// success or failure of the MakeAttemptAsync method.
        /// </summary>
        private static async Task<Attempt<List<string>>> HandleAsync(bool flag)
        {
            Task<List<string>> task = MakeAttemptAsync(flag);
            return await Attempt.ResultAsync(task);
        }

        /// <summary>
        /// Simple dummy method that returns a List or throws an exception.
        /// </summary>
        private static List<string> MakeAttempt(bool flag)
        {
            return flag
                ? SuccessList
                : throw new Exception("Failed attempt");
        }

        /// <summary>
        /// Simple dummy method that returns a successful or failed task.
        /// </summary>
        private static Task<List<string>> MakeAttemptAsync(bool flag)
        {
            return flag
                ? Task.FromResult(SuccessList)
                : Task.FromException<List<string>>(new Exception("Failed attempt"));
        }

        [Fact]
        public void Handle_Failure_ExceptionReturned()
        {
            Attempt<List<string>> attempt = Handle(false);

            Assert.False(attempt.Success);
            Assert.Null(attempt.Result);
            Assert.Equal("Failed attempt", attempt.Exception.Message);
        }

        [Fact]
        public void Handle_Success_ListReturned()
        {
            Attempt<List<string>> attempt = Handle(true);

            Assert.True(attempt.Success);
            Assert.Equal(SuccessList, attempt.Result);
            Assert.Null(attempt.Exception);
        }

        [Fact]
        public async Task HandleAsync_Failure_ExceptionReturned()
        {
            Attempt<List<string>> attempt = await HandleAsync(false);

            Assert.False(attempt.Success);
            Assert.Null(attempt.Result);
            Assert.Equal("Failed attempt", attempt.Exception.Message);
        }

        [Fact]
        public async Task HandleAsync_Success_ListReturned()
        {
            Attempt<List<string>> attempt = await HandleAsync(true);

            Assert.True(attempt.Success);
            Assert.Equal(SuccessList, attempt.Result);
            Assert.Null(attempt.Exception);
        }
    }

更新2020-01-26

我通过添加新的静态Attempt实用程序类来修改上述示例,该类有助于缩短调用代码。例如,代替编写:

    return await Attempt<List<string>>.ResultAsync(task);

您可以写:

    return await Attempt.ResultAsync(task);

因为TResulttask参数中隐含。其次,我添加了一个使用ResutOf的{​​{1}}方法,因此您无需使用Func<TResult>将同步结果转换为任务。

答案 1 :(得分:0)

您可以检查“ Rail Oriented Programming”,这正是您要实现的目标。

例如,进行多次尝试时,只有在上一次尝试成功时才应执行下一次尝试。

public Attempt<List<Strategy>> Process(params AttemptHandler[] handlers)
{
    var attempt = default(Attempt<List<Strategy>>);
    foreach(var handler in handlers)
    {
        attempt = handler.List();
        if (attempt.Failed)
        {
            return attempt.Error;
        }
    }

    return attempt.Result.ToList();
}

不是使用null作为attempt变量的默认值,而是使用“空”尝试对象,如果没有提供处理程序,它将返回空尝试。

用法

var attempt = Process(_handler1, _handler2, _handler3);