【问题标题】:Serialize Dictionary<string, string> with key having object structure使用具有对象结构的键序列化 Dictionary<string, string>
【发布时间】:2020-03-23 12:37:49
【问题描述】:

假设我有以下复杂对象:

public class Customer
    {
        public List<Contact> Contacts { get; set; }
        public class Contact
        {
            public string Adresse { get; set; }
            public string Email { get; set; }
        }
    }

我有一个Dictionary&lt;string, string&gt;,其中包含以下数据:

我怎样才能序列化这个字典来得到下面的 json 字符串? :

{
   "Contacts":[
      {
         "Adresse":"39 Dummy Street",
         "Email":"dummymail_1@dummy.com"
      },
      {
         "Adresse":"455 Dummy Street",
         "Email":"dummymail_2@dummy.com"
      },
      {
         "Adresse":"72 Dummy Street",
         "Email":"dummymail_3@dummy.com"
      }
   ]
}

【问题讨论】:

  • 您必须使用字典中的联系人实例填充Custommer 对象。不过,我不懂你的字典。字典的键实际上是"custommer.contacts[0].adresse",作为字符串吗?您是否打算使用反射来发现该字符串引用了Adresse 属性?
  • 我的困惑来自Dictionary&lt;string, string&gt; 不能将复杂对象作为其键。它有一个字符串。
  • Lasse V.Karlsen, custommer.contacts[0].adresse 是键,它是一个字符串。
  • new Custommer { Contacts = dictionary.Values.Select(a =&gt; new Custommer.Contact { Adresse = a }).ToList() }; 怎么样?
  • 为了简单起见,我只是添加了一个属性“Adresse”,但实际上对象可以更复杂。我更新了添加属性“电子邮件”的问题。

标签: .net serialization


【解决方案1】:

为了做你想做的事,既然你已经提供了一个更完整的问题,你需要执行以下步骤:

  1. 对于每个键,提取索引号和属性名称
  2. 然后,根据您在第 1 点中找到的索引,确保联系人列表中有一个联系人对象,用于 [index] 索引
  3. 使用键中的属性名称,将与键相关的字典中的值分配给相关联系人对象上的正确属性

这里有一段代码可以做到这一点:

void Main()
{
    var dict = new Dictionary<string, string>
    {
        ["customer.contacts[0].adresse"] = "39 Dummy Street",
        ["customer.contacts[0].email"] = "customer39@domain.com",
        ["customer.contacts[1].adresse"] = "455 Dummy Street",
        ["customer.contacts[1].email"] = "customer455@domain.com",
        ["customer.contacts[2].adresse"] = "72 Dummy Street",
        ["customer.contacts[2].email"] = "customer72@domain.com",
    };

    var c = new Customer { Contacts = new List<Customer.Contact>() };
    var re = new Regex(@"^customer.contacts\[(?<idx>\d+)\]\.(?<prop>.*)$");
    foreach (var (key, value) in dict)
    {
        var ma = re.Match(key);
        if (!ma.Success)
            continue;

        int index = int.Parse(ma.Groups["idx"].Value);
        string prop = ma.Groups["prop"].Value;

        while (index >= c.Contacts.Count)
            c.Contacts.Add(new Customer.Contact());

        switch (prop)
        {
            case "adresse":
                c.Contacts[index].Adresse = value;
                break;
                
            case "email":
                c.Contacts[index].Email = value;
                break;
        }
    }
    
    Console.WriteLine(JsonConvert.SerializeObject(c, Newtonsoft.Json.Formatting.Indented));
}

public class Customer
{
    public List<Contact> Contacts { get; set; }
    public class Contact
    {
        public string Adresse { get; set; }
        public string Email { get; set; }
    }
}

您可以在 dotnetfiddle 上看到它的实际效果。

上面的输出将是:

{
  "Contacts": [
    {
      "Adresse": "39 Dummy Street",
      "Email": "customer39@domain.com"
    },
    {
      "Adresse": "455 Dummy Street",
      "Email": "customer455@domain.com"
    },
    {
      "Adresse": "72 Dummy Street",
      "Email": "customer72@domain.com"
    }
  ]
}

请注意以下事项:

  1. 如果您的键跳过索引,您将在 Contacts 集合中获得空的 Contact 对象。那里会有一个实例,但没有设置任何属性。例如,您的字典有 [0]、[1] 和 [3] 的键,但缺少 [2]。 [2] 将有一个 Contact 对象,但它具有默认属性值。
  2. 没有错误检查您正在设置任何联系人对象的所有属性。例如,您有一个 "customer.contacts[2].xyz" 来获取索引 [2] 的联系人对象就足够了,但属性名称 "xyz" 将不匹配任何内容,并且如果您没有任何其他提及 [2] ,地址和电子邮件都将留空。

【讨论】:

  • @marc_s sigh 您能否也修复问题中的屏幕截图? +所有的cmets?你经历了修复问题和我的答案的麻烦,但现在截图和 cmets 讲述了一个稍微不同的故事。
  • 不,我不能——我既不能“重做”屏幕截图(因为我一开始没有这样做),我也不能编辑 cmets
猜你喜欢
  • 2011-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多