这可能是不可能的,但是我心中的强迫症至少要问是否有办法:)
我有这种方法:
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;
答案 0 :(得分:1)
这里是:
Attempt<TResult>
类的简单实现,使您可以完成想要实现的目标和为简化起见,该示例使用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);
}
}
我通过添加新的静态Attempt
实用程序类来修改上述示例,该类有助于缩短调用代码。例如,代替编写:
return await Attempt<List<string>>.ResultAsync(task);
您可以写:
return await Attempt.ResultAsync(task);
因为TResult
从task
参数中隐含。其次,我添加了一个使用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);