我们有以下课程......
public class ValueHolder<T>
{
public T Value { get; set; }
public Type ValueType => typeof(T);
}
...我们当然可以像这样实例化。
var foo = new ValueHolder<string>() { Value = "Hello World!" };
var laa = new ValueHolder<int>() { Value = 44 };
当我们使用NewtonSoft的Json.NET序列化foo
和laa
时,我们得到以下输出......
// foo
{
"Value": "Hello World!",
"ValueType": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
}
// laa
{
"Value": 44,
"ValueType": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
}
问题是反序列化它,因为Json.NET不知道它指的是泛型,所以它会爆炸。因此,我需要为此类编写自定义转换器。但是,我不确定如何实例化一个新的通用实例,其中ValueHolder中用于'T'的数据类型以字符串形式存储在ValueType中。
更多信息
我实际上是在尝试序列化/反序列化Dictionary<string,ValueHolder<>>
的子类,其中ValueHolder的T对于每个实例都可以是不同的(当然你不能这样做我实际上是子类化Dictionary<string,object>
然后将已解析的ValueHolder放入'对象')所以我认为正确的方法是将转换器放在字典上而不是ValueHolder本身。
答案 0 :(得分:0)
将你的课程拆分为:
public class ValueTypeBase
{
public Type ValueType { get; set; }
}
public class ValueHolder<T> : ValueTypeBase
{
public T Value { get; set; }
}
并查看此代码:
var json = "{\"Value\": \"Hello World!\",\"ValueType\": \"System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"}";
var valueTypeBase = JsonConvert.DeserializeObject<ValueTypeBase>(json);
var newType = typeof(ValueHolder<>).MakeGenericType(valueTypeBase.ValueType);
var obj = JsonConvert.DeserializeObject(json, newType);
答案 1 :(得分:0)
要从程序集名称创建新对象,可以使用:
Activator.CreateInstance()
方法。请参阅此处的文档:
https://msdn.microsoft.com/en-us/library/system.activator.createinstance%28v=vs.110%29.aspx
答案 2 :(得分:0)
将ValueHolder类更改为:
public class ValueHolder<T>
{
public ValueHolder() { }
public ValueHolder(T v)
{
Value = v;
}
public T Value { get; set; }
public Type ValueType() { return typeof(T); }
}
然后使用此代码:
Type d1 = typeof(ValueHolder<>);
//Your type -> "System.String"
Type typeArgs = System.Type.GetType("System.String", false, true);
Type constructed = d1.MakeGenericType(typeArgs);
//Your Value-> "Test Value"
var o = Activator.CreateInstance(constructed, "Test Value");
答案 3 :(得分:0)
使用System.Type.GetType和Type.MakeGenericType重建价值不是问题(感谢Ali Amanzadegan和Maarten):
var foo = new ValueHolder<string>() { Value = "Hello World!" };
var laa = new ValueHolder<int>() { Value = 44 };
var daa = new ValueHolder<double> { Value = 123.999 };
//
var jsonFoo = JsonConvert.SerializeObject(foo);
var jsonLaa = JsonConvert.SerializeObject(laa);
var jsonDaa = JsonConvert.SerializeObject(daa);
//
Console.WriteLine(String.Format("{0}{3}{1}{3}{2}", jsonFoo, jsonLaa, jsonDaa, Environment.NewLine));
//
var o = JsonConvert.DeserializeObject<JObject>(jsonFoo);
var typeDescription = o.Properties().FirstOrDefault(p => p.Name == "ValueType");
var type = System.Type.GetType(typeDescription.Value.ToString());
var reFoo = (dynamic)JsonConvert.DeserializeObject(jsonFoo, typeof(ValueHolder<>).MakeGenericType(type));
Console.WriteLine(reFoo.Value);
输出:
Hello World!
我遇到的困难是找到一种方法来提取函数/方法中的功能。我带来的一个可能的解决方案是再次使用动态:
private dynamic reconstructValueHolderFromJson(string json)
{
var o = JsonConvert.DeserializeObject<JObject>(json);
var typeDescription = o.Properties().FirstOrDefault(p => p.Name == "ValueType");
var type = System.Type.GetType(typeDescription.Value.ToString());
return JsonConvert.DeserializeObject(json, typeof(ValueHolder<>).MakeGenericType(type));
}
现在重建对象看起来像这样(打印值):
var reFoo = reconstructValueHolderFromJson(jsonFoo);
Console.WriteLine("{0}", reFoo.Value);
var reLaa = reconstructValueHolderFromJson(jsonLaa);
Console.WriteLine("{0}", reLaa.Value);
var reDaa = reconstructValueHolderFromJson(jsonDaa);
Console.WriteLine("{0}", reDaa.Value);
输出:
Hello World!
44
123,999