【问题标题】:C# Mapping a list to numbered variablesC# 将列表映射到编号变量
【发布时间】:2022-01-19 02:10:44
【问题描述】:

是的,我很清楚不会这样做,但我别无选择。我同意这是一个 XYZ 问题,但由于我无法更新我拥有要使用的服务,所以它不在我的掌控之中。我需要一些帮助来节省一些时间,也许可以在此过程中学到一些方便的东西。

我希望将模型列表(本示例中的项目)映射到我要发布到的服务的基本编号变量,在示例中,这是新“newUser”的一部分的字段。

此外,列表中可能并不总是有 X 数量的项目(在示例的右侧),但我有一个有限数量(比如 10)的编号变量从“newUser”映射到(在留在示例中)。所以我必须执行一系列检查以避免索引空值。

当前示例:

if (items.Count >= 1 && !string.IsNullOrWhiteSpace(items[0].id))
{
    newUser.itemId1 = items[0].id;
    newUser.itemName1 = items[0].name;
    newUser.itemDate1 = items[0].date;
    newUser.itemBlah1 = items[0].blah;
}
else
{
    // This isn't necessary, but this effectively what will happen
    newUser.itemId1 = string.Empty;
    newUser.itemName1 = string.Empty;
    newUser.itemDate1 = string.Empty;
    newUser.itemBlah1 = string.Empty;
}


if (items.Count >= 2 && !string.IsNullOrWhiteSpace(items[1].id))
{
    newUser.itemId2 = items[1].id;
    newUser.itemName2 = items[1].name;
    newUser.itemDate2 = items[1].date;
    newUser.itemBlah2 = items[1].blah;
}

// Removed the else to clean it up, but you get the idea.
// And so on, repeated many more times..

我查看了一个使用 Dictionary 的示例,但我不确定如何在不手动映射所有变量的情况下将其映射到模型。

PS:对于所有遇到这个问题的人,如果您在 API 中实现编号变量,请不要 - 这是非常不必要且耗时的。

【问题讨论】:

  • 我很困惑,你的意思是还有另一个对象叫newUser.itemId2
  • 是的,还有 itemId3 和 itemId4 等等。抱歉,让我更新一下问题,希望能更清楚一点。
  • 澄清一下,newUser 模型的生成纯粹是为了发布到另一个服务吗?可以采用的一种方法是将此请求模型构建为 JSON 表示的字符串并将其传递为 StringContent
  • 噢,这实际上并不是一个坏主意。模型的其余部分非常大,但我不明白为什么我不能将这些字段附加/替换为已经生成的 JSON 的一些构建字符串,我将不得不研究一下。感谢您的想法!
  • 你可以编写一个自定义的 json 序列化器来执行翻译,这样item[1].name => itemname1.

标签: c# list mapping


【解决方案1】:

作为摆弄 JSON 的替代方法,您可以使用Reflection

给定以下测试数据:

const int maxItemsToSend = 3;
class ItemToSend {
    public string
        itemId1, itemName1,
        itemId2, itemName2,
        itemId3, itemName3;
}
ItemToSend newUser = new();

record Item(string id, string name);
Item[] items = { new("1", "A"), new("2", "B") };

使用您在问题中提出的规则,我们可以循环遍历投影字段:

// If `itemid1`,`itemId2`, etc are fields:
var fields = typeof(ItemToSend).GetFields();
// If they're properties, replace GetFields() with 
// .GetProperties(BindingFlags.Instance | BindingFlags.Public);

for(var i = 1; i <= maxItemsToSend; i++){
    // bounds check
    var item = (items.Count() >= i && !string.IsNullOrWhiteSpace(items[i-1].id))
        ? items[i-1] : null;
    
    // Use Reflection to find and set the fields
    fields.FirstOrDefault(f => f.Name.Equals($"itemId{i}"))
        ?.SetValue(newUser, item?.id ?? string.Empty);

    fields.FirstOrDefault(f => f.Name.Equals($"itemName{i}"))
        ?.SetValue(newUser, item?.name ?? string.Empty);
}

它不漂亮,但它有效。这是fiddle

【讨论】:

    猜你喜欢
    • 2021-04-24
    • 2011-09-11
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    • 2021-05-24
    • 2019-12-26
    • 1970-01-01
    • 2020-05-25
    相关资源
    最近更新 更多