使用Asp.Net将Dictionary<string, object>反序列化为对象

5
什么是最好的反序列化方法?
Dictionary<string, object>{
   {"fName", "John"},
   {"lName", "Doe"},
   {"email", "john@doe.net"}
}

转换成这样

class Member{
   string fName;
   string lName;
   string email;
}
6个回答

5

NewtonSoft在ASP.NET应用程序中变得如此普遍,以至于如果我需要一种简短而简单的解决方案来进行此类映射,我可以使用以下代码。当然,如果它尚未存在,则引入第三方库可能有些不恰当,但有时我们只是使用可行的方法。而Newtonsoft就是这样的!

using Newtonsoft.Json;
class SerializationTests
{
    public void DictionarySerializeSample()
    {

        var dict = new Dictionary<string, object>
        {
            {"fName", "John"},
            {"lName", "Doe"},
            {"email", "john@doe.net"}
        };

        string dictInJson = JsonConvert.SerializeObject(dict);
        var member = JsonConvert.DeserializeObject<Member>(dictInJson);

        // use Newtonsoft to write out the object re-serialized
        Console.WriteLine(JsonConvert.SerializeObject(member, Formatting.Indented));

    }

    public class Member
    {
        public string fName;
        public string lName;
        public string email;
    }
}

2

这并不是通常意义上的序列化,它通常指将磁盘或网络格式化数据(二进制、ASCII、JSON等)加载到运行时对象中。

然而,如果我理解你的意思正确,我认为你想要做的是...

public Member( Dictionary<string,object> dictionary )
{ 
    fName = dictionary["fName"];
    lName = dictionary["lName"];
    email = dictionary["email"];
}

// usage Member m = new Member( inputDictionary );

我曾经考虑过这个问题,但是我不喜欢硬编码任何值的想法。这就是为什么我在询问是否有任何避免这种方法的最佳方式。简单地说,我正在寻找像这样的东西 Member member = (Member)myDictionary; - Maksim Vi.
我会将它放在一个以字典为参数的Member构造函数中。添加到答案中... - µBio
如果你想避免硬编码的键值,那么我会使用像@KiethS提供的反射技术。 - µBio
@negative:所以项目始终只有3个?还是可能会更多?例如fName,lName,email和Address。 - KMån
@KMan,是的,会有更多,Member类只是一个示例。 - Maksim Vi.

2

如果结构是静态的:

return new Member 
{
   fName = myDictionary["fName"], 
   lName = myDictionary["lName"], 
   email = myDictionary["email"]
};

如果设计时不知道结构:
public static T Hydrate<T>(this Dictionary<string, string> theDictionary, 
   T myObject = new T()) where T:new() //default/optional parameter is valid in 4.0 only
{

   //var myObject = myObject ?? new T(); //alternative in 3.5 and previous

   foreach(string key in myDictionary.Keys)
   {
      var propInfo = typeof(T).GetProperty(key);

      if(propInfo == null) throw new ArgumentException("key does not exist");
      propInfo.SetValue(myObject, theDictionary[key], null);
   }
   return myObject;
}

我认为我的类肯定有问题,因为 typeof(T).GetProperty(key) 总是为空,而 typeof(T).GetProperties() 也是空的。与 typeof(Member).GetProperties() 相同。 - Maksim Vi.

1
这不是序列化,而是转换。如果你真的想要它可转换,那就让它可转换。实现 TypeConverter
示例代码
using System;

使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text; 使用 System.IO; 使用 System.Xml.Linq; 使用 System.Diagnostics; 使用 System.Xml.Serialization; 使用 System.ComponentModel; 使用 System.Globalization;

命名空间 ConsoleApplication1 {

internal class MemberConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context,
  Type sourceType)
    {
        if (sourceType == typeof(Dictionary<string, object>))
        {
            return true;
        }
        return base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context,
  CultureInfo culture, object value)
    {
        if (value is Dictionary<string, object>)
        {
            Member member = new Member();
            Dictionary<string, object> d = (Dictionary<string, object>)value;
            if (d.ContainsKey("fName")) { member.fName = Convert.ToString(d["fName"]); };
            if (d.ContainsKey("lName")) { member.lName = Convert.ToString(d["lName"]); };
            if (d.ContainsKey("email")) { member.email = Convert.ToString(d["email"]); };
            return member;
        }
        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context,
  CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(Dictionary<string, object>))
        {
            Member member = (Member)value;
            Dictionary<string, object> d = new Dictionary<string, object>();
            d.Add("fName", member.fName);
            d.Add("lName", member.lName);
            d.Add("email", member.email);
            return d;
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }

}

[TypeConverter(typeof(MemberConverter))]
internal class Member
{
    public string fName;
    public string lName;
    public string email;
}

class Program
{
    static void Main(string[] args)
    {
        var d = new Dictionary<string, object> {
           {"fName", "John"},
           {"lName", "Doe"},
           {"email", "john@doe.net"}
        };

        Member m = (Member)TypeDescriptor.GetConverter(typeof(Member)).ConvertFrom(d);

        Debugger.Break();
    }
}

}


0

一个看起来很有道理的方法是为此编写一个静态辅助函数。

public static Member Create(Dictionary<string, object inputs)
{
    Member oNew = new Member();
    oNew.fName = inputs["fName"].ToString();
    // etc
    return oNew;
}

0
你也可以使用反射来实现这个功能,但是根据你实际使用的对象,可能需要编写大量代码,不过这种方法会更加灵活。这可能不是一个完整的示例,但它可以让你了解一般的思路。
public T InstantiateFromDictionary<T>(Dictionary<string, object> values) where T : new()
{
   Type t = typeof(T);
   T instance = new T();
   foreach(KeyValuePair<string, object> kvp in values)
   {
        PropertyInfo prop = t.GetProperty(kvp.Key);
        prop.SetValue(instance, kvp.Value, null);
   }

   return instance;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接