是否有方法将JSON内容反序列化为c#动态类型?为了使用DataContractJsonSerializer,最好跳过创建一堆类。


当前回答

我做了一个使用Expando对象的DynamicJsonConverter的新版本。我使用了expando对象,因为我想使用Json.NET将动态序列化回JSON。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Web.Script.Serialization;

public static class DynamicJson
{
    public static dynamic Parse(string json)
    {
        JavaScriptSerializer jss = new JavaScriptSerializer();
        jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });

        dynamic glossaryEntry = jss.Deserialize(json, typeof(object)) as dynamic;
        return glossaryEntry;
    }

    class DynamicJsonConverter : JavaScriptConverter
    {
        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");

            var result = ToExpando(dictionary);

            return type == typeof(object) ? result : null;
        }

        private static ExpandoObject ToExpando(IDictionary<string, object> dictionary)
        {
            var result = new ExpandoObject();
            var dic = result as IDictionary<String, object>;

            foreach (var item in dictionary)
            {
                var valueAsDic = item.Value as IDictionary<string, object>;
                if (valueAsDic != null)
                {
                    dic.Add(item.Key, ToExpando(valueAsDic));
                    continue;
                }
                var arrayList = item.Value as ArrayList;
                if (arrayList != null && arrayList.Count > 0)
                {
                    dic.Add(item.Key, ToExpando(arrayList));
                    continue;
                }

                dic.Add(item.Key, item.Value);
            }
            return result;
        }

        private static ArrayList ToExpando(ArrayList obj)
        {
            ArrayList result = new ArrayList();

            foreach (var item in obj)
            {
                var valueAsDic = item as IDictionary<string, object>;
                if (valueAsDic != null)
                {
                    result.Add(ToExpando(valueAsDic));
                    continue;
                }

                var arrayList = item as ArrayList;
                if (arrayList != null && arrayList.Count > 0)
                {
                    result.Add(ToExpando(arrayList));
                    continue;
                }

                result.Add(item);
            }
            return result;
        }

        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override IEnumerable<Type> SupportedTypes
        {
            get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
        }
    }
}

其他回答

你可以扩展JavaScriptSerializer来递归复制它创建的字典来扩展对象,然后动态地使用它们:

static class JavaScriptSerializerExtensions
{
    public static dynamic DeserializeDynamic(this JavaScriptSerializer serializer, string value)
    {
        var dictionary = serializer.Deserialize<IDictionary<string, object>>(value);
        return GetExpando(dictionary);
    }

    private static ExpandoObject GetExpando(IDictionary<string, object> dictionary)
    {
        var expando = (IDictionary<string, object>)new ExpandoObject();

        foreach (var item in dictionary)
        {
            var innerDictionary = item.Value as IDictionary<string, object>;
            if (innerDictionary != null)
            {
                expando.Add(item.Key, GetExpando(innerDictionary));
            }
            else
            {
                expando.Add(item.Key, item.Value);
            }
        }

        return (ExpandoObject)expando;
    }
}

然后,您只需要为您在其中定义扩展的名称空间使用一个using语句(考虑在System.Web.Script.Serialization中定义它们…)另一个技巧是不使用命名空间,那么你根本不需要using语句),你可以像这样使用它们:

var serializer = new JavaScriptSerializer();
var value = serializer.DeserializeDynamic("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

var name = (string)value.Name; // Jon Smith
var age = (int)value.Age;      // 42

var address = value.Address;
var city = (string)address.City;   // New York
var state = (string)address.State; // NY

我需要的是返回一个带有不同字段的json模型。 我的模型是这样的,但它可以改变。

{
    "employees":
    [
        { "name": "Darth", "surname": "Vader", "age": "27", "department": "finance"},
        { "name": "Luke", "surname": "Skywalker", "age": "25", "department": "IT"},
        { "name": "Han", "surname": "Solo", "age": "26", "department": "credit"}
    ]
}

获取数据值的列表

    JObject array = JObject.Parse(model.JsonData);
    var tableData = new List<JsonDynamicModel>();

    foreach (var objx in array.Descendants().OfType<JProperty>().Where(p => p.Value.Type != JTokenType.Array && p.Value.Type != JTokenType.Object))
            {
                var name = ((JValue)objx.Name).Value;
                var value = ((JValue)objx.Value).Value;
                if (tableData.FirstOrDefault(x => x.ColumnName == name.ToString()) == null)
                {
                    tableData.Add(new JsonDynamicModel
                    {
                        ColumnName = name.ToString(),
                        Values = new List<string> { value.ToString() },
                    });
                }
                else
                {
                    tableData.FirstOrDefault(x=>x.ColumnName == name.ToString()).Values.Add(value.ToString());
                }
            }

输出如下所示。然后我把结果模型转换成一个html表,我用这个方法创建了一个html表

// output
tableData[0].ColumnName -> "name";
tableData[0].Values -> {"Darth", "Luke", "Han" }
tableData[1].ColumnName -> "surname";
tableData[1].Values -> {"Vader", "Skywalker", "Solo" }
...

在JSON中反序列化。NET可以使用包含在该库中的JObject类来实现动态。我的JSON字符串表示这些类:

public class Foo {
   public int Age {get;set;}
   public Bar Bar {get;set;}
}

public class Bar {
   public DateTime BDay {get;set;}
}

现在我们在不引用上述类的情况下反序列化字符串:

var dyn = JsonConvert.DeserializeObject<JObject>(jsonAsFooString);

JProperty propAge = dyn.Properties().FirstOrDefault(i=>i.Name == "Age");
if(propAge != null) {
    int age = int.Parse(propAge.Value.ToString());
    Console.WriteLine("age=" + age);
}

//or as a one-liner:
int myage = int.Parse(dyn.Properties().First(i=>i.Name == "Age").Value.ToString());

或者如果你想深入一点:

var propBar = dyn.Properties().FirstOrDefault(i=>i.Name == "Bar");
if(propBar != null) {
    JObject o = (JObject)propBar.First();
    var propBDay = o.Properties().FirstOrDefault (i => i.Name=="BDay");
    if(propBDay != null) {
        DateTime bday = DateTime.Parse(propBDay.Value.ToString());
        Console.WriteLine("birthday=" + bday.ToString("MM/dd/yyyy"));
    }
}

//or as a one-liner:
DateTime mybday = DateTime.Parse(((JObject)dyn.Properties().First(i=>i.Name == "Bar").First()).Properties().First(i=>i.Name == "BDay").Value.ToString());

完整的示例请参见文章。

JsonFx可以将JSON内容反序列化为动态对象。

序列化动态类型(.NET 4.0的默认值):

var reader = new JsonReader(); var writer = new JsonWriter();

string input = @"{ ""foo"": true, ""array"": [ 42, false, ""Hello!"", null ] }";
dynamic output = reader.Read(input);
Console.WriteLine(output.array[0]); // 42
string json = writer.Write(output);
Console.WriteLine(json); // {"foo":true,"array":[42,false,"Hello!",null]}

最简单的方法是:

只需包含这个DLL文件。

像这样使用代码:

dynamic json = new JDynamic("{a:'abc'}");
// json.a is a string "abc"

dynamic json = new JDynamic("{a:3.1416}");
// json.a is 3.1416m

dynamic json = new JDynamic("{a:1}");
// json.a is

dynamic json = new JDynamic("[1,2,3]");
/json.Length/json.Count is 3
// And you can use json[0]/ json[2] to get the elements

dynamic json = new JDynamic("{a:[1,2,3]}");
//json.a.Length /json.a.Count is 3.
// And you can use  json.a[0]/ json.a[2] to get the elements

dynamic json = new JDynamic("[{b:1},{c:1}]");
// json.Length/json.Count is 2.
// And you can use the  json[0].b/json[1].c to get the num.