JSON.NET System.Drawing.Color with TypeNameHandling 的序列化
本文关键字:TypeNameHandling 序列化 with Color NET System Drawing JSON | 更新日期: 2023-09-27 18:34:46
我想序列化可能包含System.Drawing.Color
值或其他类型作为值的Dictionary<string, object>
。 我创建了一个带有 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"
}
正如预期的那样,字典中A
或B
的实例具有重建所需的$type
元数据。 但Color
实例则不然。 当此 json 反序列化时,dict["Rainbow"]
是一个System.String
。
我有很多方法可以解决这个问题,但首选的解决方案是找出为什么在这种情况下序列化程序对$type
执行看似不正确的操作。
问题是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
可以将 Color 序列化和反序列化为 Int32。例如,我这样做:
private Color _TextColor;
public Color TextColor
{
get => _TextColor;
set
{
if (_TextColor != value)
{
_TextColor = value;
PropertyChangedCall("StyleProperty");
}
}
}
public int TextColorValue
{
get => _TextColor.ToArgb();
set
{
if (_TextColor != Color.FromArgb(value))
{
_TextColor = Color.FromArgb(value);
PropertyChangedCall("StyleProperty");
}
}
}
System.Drawing.Color
是一个结构,而不是 .NET 中的类。这听起来像是你问题的答案。尝试用一个类来包装它,或者创建你自己的颜色类,它应该可以解决它。