C# 如何转换列表中的每个对象<;ExpandoObject>;变成它自己的类型?

C# 如何转换列表中的每个对象<;ExpandoObject>;变成它自己的类型?,c#,json,serialization,dynamic,C#,Json,Serialization,Dynamic,我有一个变量输入定义为列表 这是jsonList反序列化的结果,jsonList是由不同结构的对象组成的JSON数组: dynamic inputs = JsonConvert.DeserializeObject<List<ExpandoObject>>(jsonList, converter); 基本上,我希望在循环内部将input对象转换为input.type中指定为字符串的相应类型 感谢您的帮助 编辑 在这里面,对于每个循环,我想做如下操作: var json =

我有一个变量
输入
定义为
列表

这是jsonList反序列化的结果,jsonList是由不同结构的对象组成的JSON数组:

dynamic inputs = JsonConvert.DeserializeObject<List<ExpandoObject>>(jsonList, converter);
基本上,我希望在循环内部将input对象转换为input.type中指定为字符串的相应类型

感谢您的帮助

编辑

在这里面,对于每个循环,我想做如下操作:

var json = JsonConvert.SerializeObject(input);
Type T = Type.GetType(string.Format("WCFService.{0}", input.Type));
T obj = JsonConvert.DeserializeObject<typeof(T)>(json); // this line fails compilation
private T convertTo<T>(string json)
{
    return (T)JsonConvert.DeserializeObject(json, typeof(T));
}

var json = // some serialized json ...
var o = convertTo<MyCustomType>(json);
煅烧类型1、煅烧类型2和最可能的煅烧类型3、4、5。。。该数组中此类对象的类型是否

解决方案

感谢大家的帮助,特别是建议使用JObject而不是ExpandoObject,这使解决方案变得更加简单和简单: 注意:“thing”永远不会起作用,因为在本例中T必须在编译时已知,但我需要在运行时确定类型,因此解决方案如下:

    public CalcOutputTypes Calculate2(string jsonList)
    {
        var jobjects = JsonConvert.DeserializeObject<List<JObject>>(jsonList);

        foreach (var jobject in jobjects)
        {
            Type runtimeType = Type.GetType(string.Format("WCFService.{0}", jobject.GetValue("TYPE")));

            var input = jobject.ToObject(runtimeType); // Here we convert JObject to the defined type that just created runtime

            // At this moment you have a strongly typed object "input" (CalcInputTypes1 or CalcInputTypes2 or...)

        }

        return new CalcOutputTypes() { STATUS = "Everything is OK !! (input was: json array of heterogeneous objects)" }; // HERE YOU RETURN CalcOutputTypes OBJECT 
    }
public calcouttypes Calculate2(字符串jsonList)
{
var jobjects=JsonConvert.DeserializeObject(jsonList);
foreach(jobjects中的var jobject)
{
Type runtimeType=Type.GetType(string.Format(“WCFService.{0}”,jobject.GetValue(“Type”));
var input=jobject.ToObject(runtimeType);//这里我们将jobject转换为刚刚创建运行时的定义类型
//此时,您有一个强类型对象“input”(CalcInputTypes1或CalcInputTypes2或…)
}
return new calcouttypes(){STATUS=“一切正常!!(输入为:异类对象的json数组)”};//这里返回calcouttypes对象
}

您可以避免使用
ExpandoObject
而直接使用,如下所示:

        var query = from obj in JsonConvert.DeserializeObject<List<JObject>>(jsonList, converter)
                    let jType = obj["Type"]
                    where jType != null
                    let type = Type.GetType(string.Format("WCFService.{0}", (string)jType))
                    where type != null
                    where obj.Remove("Type") // Assuming this is a synthetic property added during serialization that you want to remove.
                    select obj.ToObject(type);
        var objs = query.ToList();

另一种可能的解决方案是@dbc在评论中建议使用Newtonsoft.Json方法
JsonConvert.DeserializeObject(Json,type)
,如下所示:

var json = JsonConvert.SerializeObject(input);
Type T = Type.GetType(string.Format("WCFService.{0}", input.Type));
T obj = JsonConvert.DeserializeObject<typeof(T)>(json); // this line fails compilation
private T convertTo<T>(string json)
{
    return (T)JsonConvert.DeserializeObject(json, typeof(T));
}

var json = // some serialized json ...
var o = convertTo<MyCustomType>(json);
private T convertTo(字符串json)
{
返回(T)JsonConvert.DeserializeObject(json,typeof(T));
}
var json=//一些序列化的json。。。
var o=convertTo(json);
其中,
MyCustomType
是您输入的类型(
var inputType=type.GetType(string.Format(“WCFService.{0}”,input.type));

不要忘记隐式强制转换
(t)


另一种可能是使用.NET framework内置程序编写您自己的类型转换器。

您不需要ExpandoobExt列表,只需使用CustomCreationConverter,如中所述,将所有学分都添加到@JimSan即可

public class Example
{

    [Test]
    public void Test()
    {
        var json =
            "[\r\n    {\r\n        \"Name\": \"PLAN-A\",\r\n        \"Type\": \"CalcInputTypes1\",\r\n        \"CS\": 1.1111,\r\n        \"CUSTOM_DATE1\": \"2015-05-22\",\r\n        \"CUSTOM_EARN1\": 65500.0,\r\n        \"GENDER\": \"Male\"\r\n    },\r\n    {\r\n        \"Name\": \"PLAN-B\",\r\n        \"Type\": \"CalcInputTypes2\",\r\n        \"CS\": 2.22222,\r\n        \"CUSTOM_DATE2\": \"2015-05-23\",\r\n        \"CUSTOM_EARN2\": 12000.0,\r\n        \"PROVINCE\": \"Ontario\"\r\n    }\r\n]";

        var result = JsonConvert.DeserializeObject<List<Item>>(json, new JsonItemConverter());

        Assert.That(result[0], Is.TypeOf<CalcInputTypes1>());
        Assert.That(((CalcInputTypes1)result[0]).Gender, Is.EqualTo("Male"));

        Assert.That(result[1], Is.TypeOf<CalcInputTypes2>());
        Assert.That(((CalcInputTypes2)result[1]).Province, Is.EqualTo("Ontario"));
    }

    public class JsonItemConverter : Newtonsoft.Json.Converters.CustomCreationConverter<Item>
    {
        public override Item Create(Type objectType)
        {
            throw new NotImplementedException();
        }

        public Item Create(Type objectType, JObject jObject)
        {
            var type = (string)jObject.Property("Type");
            switch (type)
            {
                case "CalcInputTypes1":
                    return new CalcInputTypes1();
                case "CalcInputTypes2":
                    return new CalcInputTypes2();
            }

            throw new ApplicationException(String.Format("The given type {0} is not supported!", type));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            // Load JObject from stream
            var jObject = JObject.Load(reader);

            // Create target object based on JObject
            var target = Create(objectType, jObject);

            // Populate the object properties
            serializer.Populate(jObject.CreateReader(), target);

            return target;
        }
    }

    public abstract class Item
    {
        public string Type { get; set; }
    }

    public class CalcInputTypes1 : Item
    {
        [JsonProperty("GENDER")]
        public string Gender { get; set; }
    }

    public class CalcInputTypes2 : Item
    {
        [JsonProperty("PROVINCE")]
        public string Province { get; set; }
    }
}
公共类示例
{
[测试]
公开无效测试()
{
var-json=
“[\r\n{\r\n\'Name\”:“PLAN-A\”,\r\n\'Type\”:“Canciputtypes1\”,\r\n\'CS\”:1.1111、\r\n\'CUSTOM\u DATE1\”:“2015-05-22\”,\r\n\'CUSTOM\u EARN1\”:65500.0、\r\n\'性别\:“男性\\r\n\”,\r\r\n\'Name\:“PLAN-B\,\r\n\”,\r\r\n\“Canciputtypes2\”\“:2.22222、\r\n\“海关日期2\”:“2015-05-23\”、\r\n\“海关收入2\”:12000.0、\r\n\“省”:“安大略省”\r\n}\r\n]”;
var result=JsonConvert.DeserializeObject(json,新的JsonItemConverter());
Assert.That(结果[0],是.TypeOf());
断言:((第1类)结果[0])。性别,等于男性;
Assert.That(结果[1],是.TypeOf());
断言:((2)结果[1])省,即安大略省;
}
公共类JSONIMConverter:Newtonsoft.Json.Converters.CustomCreationConverter
{
公共重写项创建(类型objectType)
{
抛出新的NotImplementedException();
}
创建公共项(类型objectType,JObject JObject)
{
变量类型=(字符串)jObject.Property(“类型”);
开关(类型)
{
案例“1”:
返回新的类型1();
案例“2”:
返回新的puttypes2();
}
抛出新的ApplicationException(String.Format(“不支持给定类型{0}!”,type));
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
//从流中加载作业对象
var jObject=jObject.Load(读卡器);
//基于JObject创建目标对象
var target=Create(objectType,jObject);
//填充对象属性
填充(jObject.CreateReader(),目标);
回报目标;
}
}
公共抽象类项
{
公共字符串类型{get;set;}
}
公共类类型1:项
{
[JsonProperty(“性别”)]
公共字符串{get;set;}
}
公共类类型2:项
{
[JsonProperty(“省”)]
公共字符串省{get;set;}
}
}

也许有一些简单的方法可以轻松有效地映射属性,但如果没有,那么您可以通过一点反射来手动进行映射-。然后,您想对确定并转换的类型做什么?列表中是否有一组固定的类型,或者是灵活且动态的类型?重新序列化每个类型将特定的
ExpandoObject
转换为json,然后使用或将该json转换为适当的CLR类型,不要使用
ExpandoObject
。加载到
JObject
数组中,对于每个
JObject
,检查并删除type属性,然后执行。可能会重复[使用JSON.NET将异类JSON数组反序列化为协变列表][1][1]:
public class Example
{

    [Test]
    public void Test()
    {
        var json =
            "[\r\n    {\r\n        \"Name\": \"PLAN-A\",\r\n        \"Type\": \"CalcInputTypes1\",\r\n        \"CS\": 1.1111,\r\n        \"CUSTOM_DATE1\": \"2015-05-22\",\r\n        \"CUSTOM_EARN1\": 65500.0,\r\n        \"GENDER\": \"Male\"\r\n    },\r\n    {\r\n        \"Name\": \"PLAN-B\",\r\n        \"Type\": \"CalcInputTypes2\",\r\n        \"CS\": 2.22222,\r\n        \"CUSTOM_DATE2\": \"2015-05-23\",\r\n        \"CUSTOM_EARN2\": 12000.0,\r\n        \"PROVINCE\": \"Ontario\"\r\n    }\r\n]";

        var result = JsonConvert.DeserializeObject<List<Item>>(json, new JsonItemConverter());

        Assert.That(result[0], Is.TypeOf<CalcInputTypes1>());
        Assert.That(((CalcInputTypes1)result[0]).Gender, Is.EqualTo("Male"));

        Assert.That(result[1], Is.TypeOf<CalcInputTypes2>());
        Assert.That(((CalcInputTypes2)result[1]).Province, Is.EqualTo("Ontario"));
    }

    public class JsonItemConverter : Newtonsoft.Json.Converters.CustomCreationConverter<Item>
    {
        public override Item Create(Type objectType)
        {
            throw new NotImplementedException();
        }

        public Item Create(Type objectType, JObject jObject)
        {
            var type = (string)jObject.Property("Type");
            switch (type)
            {
                case "CalcInputTypes1":
                    return new CalcInputTypes1();
                case "CalcInputTypes2":
                    return new CalcInputTypes2();
            }

            throw new ApplicationException(String.Format("The given type {0} is not supported!", type));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            // Load JObject from stream
            var jObject = JObject.Load(reader);

            // Create target object based on JObject
            var target = Create(objectType, jObject);

            // Populate the object properties
            serializer.Populate(jObject.CreateReader(), target);

            return target;
        }
    }

    public abstract class Item
    {
        public string Type { get; set; }
    }

    public class CalcInputTypes1 : Item
    {
        [JsonProperty("GENDER")]
        public string Gender { get; set; }
    }

    public class CalcInputTypes2 : Item
    {
        [JsonProperty("PROVINCE")]
        public string Province { get; set; }
    }
}