使用TypeNameHandling的System.Drawing.Color的JSON.NET序列化

时间:2014-12-20 21:33:54

标签: c# json.net

我想序列化可能包含Dictionary<string, object>值或其他类型值的System.Drawing.Color。我使用TypeNameHandling.Auto创建了一个序列化程序,这适用于大多数类,但不适用于Color

示例代码:(DotNetFiddle:https://dotnetfiddle.net/UvphQO

public class Program
{
    class A { }
    class B { }

    public static void Main()
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        dict["Foo"] = new A();
        dict["Bar"] = new B();
        dict["Baz"] = new object();
        dict["Rainbow"] = Color.FromArgb(20, 20, 20, 20);

        var ser = new JsonSerializer
        {
            TypeNameHandling = TypeNameHandling.Auto
        };
        var w = new JsonTextWriter(Console.Out)
        {
            Formatting = Formatting.Indented
        };
        ser.Serialize(w, dict);
    }
}

结果输出:

{
  "Foo": {
    "$type": "Program+A, mi1i2eqo"
  },
  "Bar": {
    "$type": "Program+B, mi1i2eqo"
  },
  "Baz": {},
  "Rainbow": "20, 20, 20, 20"
}

正如所料,字典中AB的实例具有重建所需的$type元数据。但Color的实例却没有。当这个json被反序列化时,dict["Rainbow"]System.String

我有很多方法可以解决这个问题,但首选的解决方案是弄清楚为什么序列化程序在这种情况下使用$type执行看似不正确的操作。

2 个答案:

答案 0 :(得分:1)

问题是System.Drawing.Color有一个关联的TypeConverter,Json.Net使用它将类型转换为字符串值并返回。但是,由于输出值是字符串(不是复杂对象),因此Json.Net不会为其输出任何类型信息。如果您的属性被定义为object而不是强类型,则会在反序列化期间导致问题:Json.Net无法找到TypeConverter,因此无法转换字符串值返回Color

解决此问题的一种方法是将Color包装在另一个具有颜色值的强类型属性的类中。

class ColorHolder
{
    public System.Drawing.Color Value { get; set; }
}
然后,Json.Net将写出包装类的类型信息,这将允许嵌套的Color结构正确反序列化。这是一个往返演示:

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        dict["Rainbow"] = new ColorHolder { Value = Color.FromArgb(10, 20, 30, 40) };

        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Auto,
            Formatting = Formatting.Indented
        };

        string json = JsonConvert.SerializeObject(dict, settings);
        Console.WriteLine(json);
        Console.WriteLine();

        var d = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, settings);

        ColorHolder holder = (ColorHolder)d["Rainbow"];
        Console.WriteLine("A=" + holder.Value.A);
        Console.WriteLine("R=" + holder.Value.R);
        Console.WriteLine("G=" + holder.Value.G);
        Console.WriteLine("B=" + holder.Value.B);
    }
}

输出:

{
  "Rainbow": {
    "$type": "JsonTest.ColorHolder, JsonTest",
    "Value": "10, 20, 30, 40"
  }
}

A=10
R=20
G=30
B=40

答案 1 :(得分:0)

System.Drawing.Color是一个结构,而不是.NET中的类。这听起来像是你问题的答案。尝试用类包装它,或者创建自己的颜色类,它应该解决它。