在给定T的字符串表示的情况下,如何实例化SomeObject <t>的实例?

时间:2015-08-02 07:30:50

标签: c# json serialization json.net activator

我们有以下课程......

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序列化foolaa时,我们得到以下输出......

// 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本身。

4 个答案:

答案 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.GetTypeType.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