无需修改中间方法,如何向Match的Left Lambda传递额外数据?
解决方案
方案1:拆分流程为两个阶段(推荐,无需修改底层方法)
把获取发卡机构(CardIssuer)的逻辑单独抽离,先处理这一步的错误;拿到合法的CardIssuer后,再执行后续的交易查询和状态获取,此时后续所有错误都能使用已获取的密钥加密。
代码实现:
static async Task<string> Process(string cardIssuerId) { // 第一阶段:获取发卡机构,处理无密钥的错误场景 var issuerEither = await GetCardIssuer(cardIssuerId).ToAsync(); return await issuerEither.Match( async issuer => { // 第二阶段:已拿到密钥,后续所有错误都可以用该密钥加密 var transactionIdEither = await GetLatestTransactionId(issuer).ToAsync(); return await transactionIdEither.Match( async transactionId => { var statusEither = await GetCustomerStatus(transactionId).ToAsync(); return statusEither.Match( status => Encrypt(status.ToString(), issuer.Key), error => Encrypt($"Error: {error}", issuer.Key) ); }, error => Encrypt($"Error: {error}", issuer.Key) ); }, // GetCardIssuer失败时无密钥可用,直接返回原始错误 error => Task.FromResult($"Error: {error}") ); }
该方案优势:
- 完全不需要修改任何底层的
Either返回方法,避免污染可复用逻辑 - 逻辑清晰,明确区分“无密钥”和“有密钥”的错误场景
- 代码改动最小,仅调整
Process方法的结构
方案2:自定义带上下文的Either类型(适合长期复用)
如果你的代码中有大量类似场景需要携带上下文(比如密钥),可以自定义带上下文的Either类型,封装上下文传递逻辑,避免重复编写嵌套Match。
步骤1:定义带上下文的Either类型及扩展方法
// 携带上下文的Either类型,保留上下文和原始Either结果 record EitherWithContext<TContext, TLeft, TRight>(TContext Context, Either<TLeft, TRight> Either); // 扩展方法:将普通Either转换为带上下文的Either static EitherWithContext<TContext, TLeft, TRight> WithContext<TContext, TLeft, TRight>( this Either<TLeft, TRight> either, TContext context) => new EitherWithContext<TContext, TLeft, TRight>(context, either); // 扩展方法:实现Bind操作,保留上下文传递 static EitherWithContext<TContext, TLeft, TRightNew> Bind<TContext, TLeft, TRight, TRightNew>( this EitherWithContext<TContext, TLeft, TRight> eitherWithContext, Func<TRight, Either<TLeft, TRightNew>> bindFunc) => new EitherWithContext<TContext, TLeft, TRightNew>( eitherWithContext.Context, eitherWithContext.Either.Bind(bindFunc)); // 扩展方法:转换为异步类型(按需实现) static async Task<EitherWithContext<TContext, TLeft, TRight>> ToAsync<TContext, TLeft, TRight>( this EitherWithContext<TContext, TLeft, TRight> eitherWithContext) => eitherWithContext;
步骤2:在Process方法中使用
static async Task<string> Process(string cardIssuerId) { var issuerEither = await GetCardIssuer(cardIssuerId).ToAsync(); return await issuerEither.Match( async issuer => { // 链式调用时携带issuer上下文 var resultWithContext = await GetLatestTransactionId(issuer) .WithContext(issuer) .Bind(transactionId => GetCustomerStatus(transactionId)) .ToAsync(); // 统一处理成功/错误,均可用上下文密钥加密 return resultWithContext.Either.Match( status => Encrypt(status.ToString(), resultWithContext.Context.Key), error => Encrypt($"Error: {error}", resultWithContext.Context.Key) ); }, error => Task.FromResult($"Error: {error}") ); }
该方案优势:
- 上下文传递逻辑封装在类型和扩展方法中,业务代码更简洁
- 适合多个场景复用,避免重复编写嵌套
Match逻辑
关键说明
如果GetCardIssuer本身返回Left(获取发卡机构失败),此时根本没有可用的加密密钥,只能返回未加密的错误信息——这是合理的,因为密钥依赖于成功获取的CardIssuer实例,获取失败自然无法进行加密操作。
内容的提问来源于stack exchange,提问作者Avrohom Yisroel
相关产品推荐
相关产品推荐

