C#代码重构:消除连续if语句提升可读性与可维护性
是否适合使用守卫子句优化
完全适合。你当前代码的核心可读性问题就是多层嵌套的连续if把核心业务逻辑包裹得太深,阅读者需要记住每层判断的条件才能理解后续逻辑,用反向判断提前退出的守卫子句是这类场景的标准优化方案,不会改变原有业务逻辑,还能大幅降低理解成本。
除了嵌套if的问题,你这段代码还有两个明显的维护隐患:一是处理CommerceMedia集合和Rockstar自定义文档的逻辑几乎1:1重复,后续修改规则很容易漏改其中一处;二是字典更新的分支里存在大量重复代码,还有冗余的引用类型重新赋值操作。
具体优化方向
- 所有不满足执行条件的分支直接return/continue/break,把核心逻辑从嵌套块里解放出来,比如没有子节点直接返回空字典、无效媒体链接直接跳过当前循环、收到停止信号直接中断遍历。
- 抽离重复的媒体关联处理逻辑为独立私有方法,不管媒体来源是系统CommerceMedia还是自定义产品文档,只要拿到了资源链接,就走同一套关联更新逻辑,消除重复代码。
- 简化字典操作逻辑:不需要在TryGetValue的存在/不存在两个分支里重复写添加产品、添加分类的逻辑,判断key不存在时先初始化实例存入字典,后续统一更新实例属性即可——因为是引用类型,直接修改属性就会同步到字典里存储的对象,不需要再重复给字典key赋值。
- 清理冗余代码:比如已经通过
is做了类型转换判断后不需要再对转换后的对象做null检查;Guid是值类型不存在null的情况,不需要额外加null判断;空集合用Enumerable.Empty<T>()比new空List更高效。
优化后完整代码
private Dictionary<Guid, CommerceMediaFileAssociation<T>> GetMediaToContentsAssociations<T>(ref bool stopSignaled, CatalogContentBase catalog, CultureInfo culture, Action<string> onStatusChanged = null) where T : MediaData { IEnumerable<ContentReference> descendentReferences = _contentLoader.GetDescendents(catalog.ContentLink); var associations = new Dictionary<Guid, CommerceMediaFileAssociation<T>>(); // 守卫子句:无子节点直接返回 if (!descendentReferences.Any()) return associations; var descendentProducts = _contentLoader.GetItems<BaseProduct>(descendentReferences, culture); foreach (var product in descendentProducts) { // 守卫子句:收到停止信号直接中断 if (stopSignaled) { onStatusChanged?.Invoke($"Reindexing canceled."); break; } // 处理系统CommerceMedia资源 if (product is IAssetContainer assetContainer && assetContainer.CommerceMediaCollection?.Any() == true) { foreach (CommerceMedia media in assetContainer.CommerceMediaCollection) { PermanentLinkMap mediaLinkMap = _permanentLinkMapper.Find(media.AssetLink); UpdateMediaAssociation(associations, mediaLinkMap, product); } } // 处理Rockstar自定义文档资源 if (product is RockstarProduct rockstar) { var files = rockstar.Rockstar_Product_Product_Documents.FilteredItems.Select(x => x.GetContent() as IContentMedia) ?? Enumerable.Empty<IContentMedia>(); foreach (var file in files) { PermanentLinkMap mediaLinkMap = _permanentLinkMapper.Find(file.ContentLink); UpdateMediaAssociation(associations, mediaLinkMap, product); } } } return associations; } /// <summary> /// 抽离的通用媒体关联更新逻辑 /// </summary> private void UpdateMediaAssociation<T>(Dictionary<Guid, CommerceMediaFileAssociation<T>> associations, PermanentLinkMap mediaLinkMap, BaseProduct product) where T : MediaData { // 守卫子句:无效媒体链接直接跳过 if (mediaLinkMap == null || mediaLinkMap.Guid == Guid.Empty) return; var productInfo = ProductUtilities.GetProductCategoriesAndPriority(product); var mediaKey = mediaLinkMap.Guid; // 不存在关联则先初始化,后续统一处理逻辑,消除分支重复 if (!associations.TryGetValue(mediaKey, out var association)) { association = new CommerceMediaFileAssociation<T>(); associations.Add(mediaKey, association); } // 统一更新关联信息,无需在两个分支重复编写 association.Products.Add($"{product.ContentGuid}||{product.MetaTitle}"); if (productInfo.Categories?.Any() == true) { // 如果需要避免分类重复添加可以用UnionWith,不需要的话换回原来的foreach循环Add即可 association.ProductCategories.UnionWith(productInfo.Categories); } association.Priority = productInfo.Priority; }
优化后代码主逻辑缩进最多2层,流程一目了然,后续如果要新增第三种媒体来源,只需要拿到资源链接调用通用的UpdateMediaAssociation方法即可,不需要再复制大段重复逻辑。
内容的提问来源于stack exchange,提问作者cowefe
相关产品推荐
相关产品推荐

