给定 T 的字符串表示形式,如何实例化 SomeObject<T> 的实例?
Posted
技术标签:
【中文标题】给定 T 的字符串表示形式,如何实例化 SomeObject<T> 的实例?【英文标题】:How can you instantiate an instance of SomeObject<T>, given the string representation of T? 【发布时间】:2015-10-24 12:20:15 【问题描述】:我们有以下课程...
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 本身上。
【问题讨论】:
不清楚你在问什么。你想从字符串形式的类型中创建一个通用实例(类的)(??).. ???对我来说毫无意义。也许举个例子可以说明问题。 见这里:***.com/a/1371756/261050 @Maarten,MakeGenericType 看起来很有趣!用一个例子把它放在一个答案中,你就会得到荣誉。 【参考方案1】:要从程序集名称创建新对象,您可以使用:
Activator.CreateInstance()
方法。请参阅此处的文档:
https://msdn.microsoft.com/en-us/library/system.activator.createinstance%28v=vs.110%29.aspx
【讨论】:
我知道激活器。但这仍然没有回答如何激活泛型类型。例如,如果 ValueType 是 System.Int,那么我需要激活的类型是 ValueHolderToString()
创建的字符串表示。听起来是个坏方法
你想做什么?我现在明白你的问题,但可能有更好的方法来解决这个问题
Aniket,很抱歉您不理解这一点。所有细节都清楚地在问题中。不,我没有像你说的那样打电话给 ToString。这就是 Json.NET 正在写的内容,因为类型信息需要写出,因为它是反序列化所需的。
Aniket,当我还没有提出建议时,我不确定您所说的“更好的方法”是什么。正如我所说,我有 JSON,我知道它代表一个 ValueHolder把你的班级分成这样:
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);
【讨论】:
我知道,但是您只需将泛型类型的 T 值(此处为“字符串”)放入 DeserializeObject 调用中。这就是问题所在... ValueType 表示 ValueHolderjson
字符串是ValueHolder<string>
的字符串表示形式,因此只有反序列化为ValueHolder<string>
类型才有意义。您无法将其转换为 ValueHolder<T>
@Aniket,再一次,你错过了重点。我没有尝试将其转换为 ValueHolder希望对您有所帮助。
将 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");
【讨论】:
【参考方案4】:使用 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("03132", 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!
对我来说,困难在于找到一种方法来提取函数/方法中的功能。我提出的一种可能的解决方案是再次使用 dynamic:
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
【讨论】:
你的 genericValueHolder 不是多余的吗?您只是在创建该类型的实例以返回并获取其类型。换句话说,您实际上并没有使用该实例。如果您删除 CreateInstance 部分并使用 typeof(...) 开始等号之后的行,那么您将拥有直接传递给 DeserializeObject 的类型。 好点 - 你是对的。我已经删除了这部分,因为保留的代码与reconstructValueHolderFromJson
方法中的代码相同。您是否找到了获取ValueHolder<T>
类型对象的方法?
仍在努力。我实际上是在尝试序列化一个 dictionary以上是关于给定 T 的字符串表示形式,如何实例化 SomeObject<T> 的实例?的主要内容,如果未能解决你的问题,请参考以下文章