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

如何在C#中动态处理TheCocktailDB饮品的可变配料与测量字段

动态处理TheCocktailDB饮品配料与测量值的解决方案

问题背景

我正在开发一个从TheCocktailDB API获取饮品详情的项目,每种饮品最多包含15种配料及对应测量值,但实际配料数量因饮品而异。我希望以表格格式动态展示这些数据,目前遇到两个问题:

  • 无法动态处理每种饮品数量可变的配料与测量值
  • 无法在不硬编码列名的情况下将数据转换为键值对格式(如Ingredient1 -> Vodka)

现有代码

Drink类定义

public class Drink
{
    public string? strDrink { get; set; }
    public string? strIngredient1 { get; set; }
    public string? strIngredient2 { get; set; }
    // up to strIngredient15
    public string? strMeasure1 { get; set; }
    public string? strMeasure2 { get; set; }
    // up to strMeasure15
}

当前遍历代码

foreach (var drink in _drinkDetails.drinks)
{
    Console.WriteLine($"Drink Name: {drink.strDrink}");
    // How do I dynamically iterate through the ingredients and measures here?
}

解决方案

方法1:使用反射动态遍历属性

通过反射自动识别并筛选出所有配料和测量值属性,按序号配对后展示,无需硬编码属性名:

foreach (var drink in _drinkDetails.drinks)
{
    Console.WriteLine($"饮品名称: {drink.strDrink}");
    Console.WriteLine("| 配料 | 测量值 |");
    Console.WriteLine("|------|--------|");

    // 获取所有非空的配料属性并按序号排序
    var ingredientProps = typeof(Drink).GetProperties()
        .Where(p => p.Name.StartsWith("strIngredient") && p.GetValue(drink) != null)
        .OrderBy(p => p.Name)
        .ToList();

    // 获取所有非空的测量值属性并按序号排序
    var measureProps = typeof(Drink).GetProperties()
        .Where(p => p.Name.StartsWith("strMeasure") && p.GetValue(drink) != null)
        .OrderBy(p => p.Name)
        .ToList();

    // 按序号配对展示,处理数量不一致的情况
    int maxPairs = Math.Max(ingredientProps.Count, measureProps.Count);
    for (int i = 0; i < maxPairs; i++)
    {
        string ingredient = i < ingredientProps.Count ? ingredientProps[i].GetValue(drink)?.ToString() ?? "-" : "-";
        string measure = i < measureProps.Count ? measureProps[i].GetValue(drink)?.ToString() ?? "-" : "-";
        Console.WriteLine($"| {ingredient} | {measure} |");
    }
    Console.WriteLine();
}

方法2:重构Drink类,使用集合存储配料

如果允许修改Drink类,将硬编码的15组属性替换为集合,会让数据处理更简洁。可以在反序列化后转换数据:

// 重构后的Drink类
public class Drink
{
    public string? strDrink { get; set; }
    public List<(string Ingredient, string Measure)> Ingredients { get; set; } = new();
}

// 数据转换与展示代码
foreach (var rawDrink in _drinkDetails.drinks)
{
    var drink = new Drink
    {
        strDrink = rawDrink.strDrink
    };

    // 遍历1到15的属性,提取非空配料
    for (int i = 1; i <= 15; i++)
    {
        var ingredientProp = rawDrink.GetType().GetProperty($"strIngredient{i}");
        var measureProp = rawDrink.GetType().GetProperty($"strMeasure{i}");
        if (ingredientProp == null || measureProp == null) continue;

        string? ingredient = ingredientProp.GetValue(rawDrink)?.ToString();
        if (!string.IsNullOrEmpty(ingredient))
        {
            string measure = measureProp.GetValue(rawDrink)?.ToString() ?? "-";
            drink.Ingredients.Add((ingredient, measure));
        }
    }

    // 输出表格
    Console.WriteLine($"饮品名称: {drink.strDrink}");
    Console.WriteLine("| 配料 | 测量值 |");
    Console.WriteLine("|------|--------|");
    foreach (var item in drink.Ingredients)
    {
        Console.WriteLine($"| {item.Ingredient} | {item.Measure} |");
    }
    Console.WriteLine();
}

方法3:手动遍历属性(无反射)

如果不想使用反射,也可以手动编写循环遍历1到15的属性,代码稍显重复但可读性高:

foreach (var drink in _drinkDetails.drinks)
{
    Console.WriteLine($"饮品名称: {drink.strDrink}");
    Console.WriteLine("| 配料 | 测量值 |");
    Console.WriteLine("|------|--------|");

    for (int i = 1; i <= 15; i++)
    {
        string? ingredient = i switch
        {
            1 => drink.strIngredient1,
            2 => drink.strIngredient2,
            3 => drink.strIngredient3,
            4 => drink.strIngredient4,
            5 => drink.strIngredient5,
            6 => drink.strIngredient6,
            7 => drink.strIngredient7,
            8 => drink.strIngredient8,
            9 => drink.strIngredient9,
            10 => drink.strIngredient10,
            11 => drink.strIngredient11,
            12 => drink.strIngredient12,
            13 => drink.strIngredient13,
            14 => drink.strIngredient14,
            15 => drink.strIngredient15,
            _ => null
        };

        string? measure = i switch
        {
            1 => drink.strMeasure1,
            2 => drink.strMeasure2,
            3 => drink.strMeasure3,
            4 => drink.strMeasure4,
            5 => drink.strMeasure5,
            6 => drink.strMeasure6,
            7 => drink.strMeasure7,
            8 => drink.strMeasure8,
            9 => drink.strMeasure9,
            10 => drink.strMeasure10,
            11 => drink.strMeasure11,
            12 => drink.strMeasure12,
            13 => drink.strMeasure13,
            14 => drink.strMeasure14,
            15 => drink.strMeasure15,
            _ => null
        };

        if (!string.IsNullOrEmpty(ingredient))
        {
            Console.WriteLine($"| {ingredient} | {measure ?? "-"} |");
        }
    }
    Console.WriteLine();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:58:13