You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#函数式编程重构:消除缓存判断分支重复代码

C# 函数式分支重复代码重构方案

核心思路

两个分支的唯一差异是DetailsAsync接口需要的ClientUserId参数来源:

  • 缓存未命中:需要调用GetUserAsync拉取用户信息、写入缓存,再取用户ID
  • 缓存命中:直接读取缓存中存储的用户ID
    除此之外所有业务逻辑完全一致,只需要先统一拿到合法的用户ID,再执行一次公共逻辑即可,不需要在两个分支里重复编写后续流程。

方案1:保持函数式链式调用风格(适配现有代码写法)

将用户ID的获取逻辑统一收敛为同类型返回结果,和现有MapOnFailure/DoAsync扩展方法完全适配:

// 统一收敛用户ID获取逻辑,屏蔽缓存命中/未命中的分支差异
var userIdTask = _cache.TryGetValue("ClientUserId", out string cachedUserId)
    // 缓存命中直接返回成功结果,适配项目自身的Result类型即可
    ? Task.FromResult(Result<string, AppF>.Success(cachedUserId))
    : _userM.GetUserAsync(dbData.CreateEmployeeID.ToString(), cancellationToken)
        .MapOnFailure(failure => new AppF(failure.Message, failure.Exception))
        // 拉取到用户后先写入缓存
        .DoAsync(user => _cache.Set("ClientUserId", user.ClientUserId, cacheExpiration))
        // 统一返回用户ID字符串,和缓存命中的返回类型对齐
        .Map(user => user.ClientUserId);

// 拿到用户ID后执行一次公共业务逻辑,无重复代码
var userIdResult = await userIdTask;
await userIdResult.DoAsync(async clientUserId =>
{
    var opsRequest = new OperationStatusRequest();
    var results = await _monitoringService.LogHttpRequestResponseAsync(
        opsRequest,
        JsonSerializer.Serialize(cRequest),
        async () => await _client.DetailsAsync(clientUserId, cancellationToken)
            .DoAsync(async _ =>
            {
                // 公共成功处理逻辑
            })
            .DoOnFailureAsync(async _ =>
            {
                // 公共失败处理逻辑
            })
    );
    // 后续对results的处理统一写在这里
});

注:Result<string, AppF>.Success是函数式错误处理的标准构造方法,如果使用LanguageExt等第三方库、或是项目自定义的Result类型,对应调整成功返回的构造语法即可,不影响整体逻辑。


方案2:直白流程控制写法(可读性更高,无额外类型适配成本)

如果不需要保持全程链式调用,可以先通过分支拿到用户ID,再执行后续公共逻辑,代码更直观:

string clientUserId;
// 分支仅处理用户ID获取和缓存写入,不掺杂业务逻辑
if (!_cache.TryGetValue("ClientUserId", out clientUserId))
{
    var userResult = await _userM.GetUserAsync(
        dbData.CreateEmployeeID.ToString(), 
        cancellationToken)
        .MapOnFailure(failure => new AppF(failure.Message, failure.Exception));

    // 错误提前返回,和原有逻辑的错误处理行为一致
    if (userResult.IsFailure)
        return userResult.Error;

    clientUserId = userResult.Value.ClientUserId;
    _cache.Set("ClientUserId", clientUserId, cacheExpiration);
}

// 后续所有公共业务逻辑只编写一次
var opsRequest = new OperationStatusRequest();
var results = await _monitoringService.LogHttpRequestResponseAsync(
    opsRequest,
    JsonSerializer.Serialize(cRequest),
    async () => await _client.DetailsAsync(clientUserId, cancellationToken)
        .DoAsync(async _ =>
        {
            // 公共成功处理逻辑
        })
        .DoOnFailureAsync(async _ =>
        {
            // 公共失败处理逻辑
        })
);

优化说明

  • 两种方案都完全消除了重复代码,后续修改DetailsAsync调用后的业务逻辑时只需要改一处
  • 将缓存判断、用户拉取、缓存写入的逻辑和核心业务逻辑解耦,职责划分更清晰
  • 修正了原代码中operationStatusRequest和实例化变量opsRequest命名不一致的笔误

内容的提问来源于stack exchange,提问作者Joseph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 09:39:18