C#生成多规格商品SKU组合结果异常问题排查
多规格商品SKU生成逻辑错误排查
需求背景
开发库存管理系统时需要实现多规格(变体)商品SKU自动生成功能,本质是计算所有变体选项的笛卡尔积。当前支持三类变体,可选值如下:
- color:Black, Blue, Grey
- size:S, M, L, XL
- material:Cotton, Wool
现有代码在仅选择2种变体(比如color+size)时可以输出正确结果,新增第3种变体后输出不符合预期。
以商品名Jean为例,预期输出所有组合,格式如下:
- Jean-Black/S/Cotton
- Jean-Black/S/Wool
- Jean-Black/M/Cotton
- Jean-Black/M/Wool
- Jean-Black/L/Cotton
- Jean-Black/L/Wool
- Jean-Black/XL/Cotton
- Jean-Black/XL/Wool
- Jean-Blue/S/Cotton
- Jean-Blue/S/Wool
- Jean-Blue/M/Cotton
- Jean-Blue/M/Wool
- Jean-Blue/L/Cotton
- Jean-Blue/L/Wool
- Jean-Blue/XL/Cotton
- Jean-Blue/XL/Wool
- Jean-Grey/S/Cotton
- Jean-Grey/S/Wool
- Jean-Grey/M/Cotton
- Jean-Grey/M/Wool
- Jean-Grey/L/Cotton
- Jean-Grey/L/Wool
- Jean-Grey/XL/Cotton
- Jean-Grey/XL/Wool
现有代码
页面绑定模型
public class CreateModel : PageModel { [Required] [BindProperty] public string? Name { get; set; } [BindProperty] public List<ProductVariantModel> Variants { get; set; } }

变体项模型
public class ProductVariantModel { public string? Name { get; set; } public string? Options { get; set; } }
SKU生成核心逻辑
List<ProductVariantOption> productOptions = new(); try { int variantsTotal = model.Variants.Count; for (int a = 0; a < variantsTotal; a++) { string[] options = model.Variants[a].Options.Split(','); for (int i = 0; i < options.Length; i++) { string? option = $"{model.Name}-{options[i]}"; if (variantsTotal > 1) { int index = a + 1; if (index < variantsTotal) { var levelBelowOptions = model.Variants[index].Options.Split(','); var ops = GetOptions(option, levelBelowOptions); productOptions.AddRange(ops); } } } a += 1; } }
选项拼接方法
private List<ProductVariantOption> GetOptions(string option, string[] options) { List<ProductVariantOption> variantOptions = new(); for (int i = 0; i < options.Length; i++) { string sku = $"{option}/{options[i]}"; string opt = $"{option}/{options[i]}"; variantOptions.Add(new ProductVariantOption(opt, sku)); } return variantOptions; }
SKU实体定义
public class ProductVariantOption { public string Name { get; private set; } public string SKU { get; private set; } public Guid ProductVariantId { get; private set; } public ProductVariant ProductVariant { get; private set; } public ProductVariantOption(string name, string sku) { Guard.AgainstNullOrEmpty(name, nameof(name)); Name = name; SKU = sku; } }
逻辑错误说明
现有代码共3处核心问题,2种变体时属于巧合能正常运行,3种及以上变体就会完全失效:
- 外层循环索引重复自增:外层for循环本身已经定义了
a++的自增逻辑,循环块末尾又额外写了a += 1,相当于每次循环a的索引直接加2。2种变体时,a初始值为0,进入循环处理第一个变体,走完循环块a变成1,触发for循环的a++后变成2,刚好满足退出条件,不会触发异常;3种变体时,第一次循环走完a变成1,for自增后变成2,直接跳过了索引为1的size变体,进入material层级的循环,完全漏掉size维度的选项。 - 拼接逻辑硬编码仅支持2层:现有逻辑拿到当前层的选项后,只会取下一个相邻层级的选项做拼接,
GetOptions方法拼完相邻层就直接返回结果,没有继续处理后续剩余层级的逻辑,3种变体时最多只能拼出2段的SKU,根本不会带上第三层material的选项。 - 循环起始维度错误:外层循环会把每个变体层级都当作组合的起始点处理,而笛卡尔积计算只需要从第一个维度开始,逐层向后累积拼接即可,多起始点遍历会生成大量缺项、重复的无效SKU。
修复思路
放弃硬编码两层的拼接写法,改用通用笛卡尔积累积逻辑:先把第一个变体的所有选项作为初始结果集,然后依次遍历后续每一个变体,把当前结果集里的每一项和当前变体的所有选项做交叉拼接,替换原来的结果集,直到所有变体维度遍历完成,即可支持任意数量的变体组合。
内容的提问来源于stack exchange,提问作者Edgias
相关产品推荐
相关产品推荐

