我有一个方法,可以在数据库中查找会员卡,如果找到并且有效则返回它,或者返回enum
值,如果没有。这允许调用代码打开enum
价值。我想退货Either<TransactionRequestStates, Card>
,因为该方法将与几个用于获取和验证传入数据的类似方法绑定在一起。由于应该进行数据库调用async
,我需要返回EitherAsync
而不是仅仅Either
.
为了澄清这一点,我有几种方法,每种方法都执行一个特定的步骤。如果成功,每个方法都会返回一个Right
包含稍后方法使用的一些数据。如果不是,则返回一个Left
与enum
值表明出了什么问题。我想将它们组成如下(为了清楚起见,进行了简化)...
public static async Task<TransactionRequestStates> Process(
IHttpContextAccessor httpContextAccessor,
AppDbContext context, UserManager<User> userMgr,
string cardSerialNumber, string uri, int amount, string hash) {
Either<TransactionRequestStates, TransactionRequestStates> result = await (
from card in GetCard(context, cardSerialNumber, amount)
from deviceSerialNumber in GetDeviceSerialNumberFromToken(httpContextAccessor, context, userMgr)
from device in GetDevice(httpContextAccessor, context, deviceSerialNumber)
from rental in GetOrganisationRental(context, device)
from vcResponse in GetVcResponse(rental, card, amount, hash, uri)
from saveResponse in SaveResponse()
select TransactionRequestStates.Success
);
return result.Match(_ => TransactionRequestStates.Success, msg => msg);
}
这个问题涵盖了GetCard
方法,因为我假设如果我能做到这一点,其他人都会遵循类似的模式。
我可以执行以下操作...
private static EitherAsync<TransactionRequestStates, Card> GetCard(AppDbContext context, string cardSerialNumber) {
Card? card = context.Cards.SingleOrDefault(c => c.SerialNumber == cardSerialNumber);
if (card == null) {
return TransactionRequestStates.CardNotFound.AsTask();
}
if (card.Locked) {
return TransactionRequestStates.CardLocked.AsTask();
}
// Quite a few more checks are done in the real code. If we pass them all, return the card...
return card.AsTask();
}
然而,这都是同步代码。我希望数据库调用是异步的。根据我从 Guru Stron 那里得到的答案上一个问题 https://stackoverflow.com/a/72901808/706346,我知道我可以做这样的事情......
static EitherAsync<string, int> Square2(int n) =>
TryAsync(async () =>
{
await Task.Delay(300);
throw new Exception();
return n * n;
})
.ToEither(error => error.Message);
但是,我不想返回string
如果出现异常,我想返回一个enum
值,如上图所示。
我不知道该怎么做。如果我尝试返回enum
直接值...
private static EitherAsync<TransactionRequestStates, Card> GetCard2(AppDbContext context, string cardSerialNumber) =>
TryAsync(async () => {
Card? card = await context.Cards.SingleOrDefaultAsync(c => c.SerialNumber == cardSerialNumber);
if (card == null) {
return TransactionRequestStates.CardNotFound.AsTask();
}
if (card.Locked) {
return TransactionRequestStates.CardLocked.AsTask();
}
return card;
});
...然后我收到编译器错误“无法从用法中推断出方法“Prelude.TryAsync(Func)”的类型参数。尝试显式指定类型参数“。我对此类错误的经验表明我的代码是错误的,就好像它是正确的一样,编译器应该能够推断出类型。
我尝试返回Left<TransactionRequestStates, Card>(TransactionRequestStates.CardNotFound)
(有或没有打电话AsTask()
最后),但这并没有改变错误。我还尝试将呼叫添加到ToEither()
最后,但这也没有帮助。
任何人都能够解释我需要做什么才能返回EitherAsync<TransactionRequestStates, Card>
? Thanks