我们有以下类…
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序列化foo
和laa
时。. NET,我们得到以下输出…
// 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本身。
要从程序集名称创建新对象,可以使用:
Activator.CreateInstance()
方法。请参阅此处的文档:
将class拆分为:
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);
希望对您有所帮助。
将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");
使用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