将JSON反序列化为C#动态对象?

有没有办法将JSON内容反序列化为C#动态类型?最好跳过创建一堆类以使用DataContractJsonSerializer

1030359 次浏览

为此,我将使用JSON.NET对JSON流进行低级解析,然后从ExpandoObject类的实例构建对象层次结构。

如果您乐于依赖于System.Web.Helpers程序集,那么您可以使用#1类:

dynamic data = Json.Decode(json);

它作为额外下载包含在MVC框架中。NET 4框架。如果有帮助,请务必给予Vlad赞成票!但是,如果您不能假设客户端环境包含此DLL,请继续阅读。


建议这里使用另一种反序列化方法。我稍微修改了代码以修复bug并适合我的编码风格。你需要的就是这段代码和对项目System.Web.Extensions的引用:

using System;using System.Collections;using System.Collections.Generic;using System.Collections.ObjectModel;using System.Dynamic;using System.Linq;using System.Text;using System.Web.Script.Serialization;
public sealed class DynamicJsonConverter : JavaScriptConverter{public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer){if (dictionary == null)throw new ArgumentNullException("dictionary");
return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;}
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) })); }}
#region Nested type: DynamicJsonObject
private sealed class DynamicJsonObject : DynamicObject{private readonly IDictionary<string, object> _dictionary;
public DynamicJsonObject(IDictionary<string, object> dictionary){if (dictionary == null)throw new ArgumentNullException("dictionary");_dictionary = dictionary;}
public override string ToString(){var sb = new StringBuilder("{");ToString(sb);return sb.ToString();}
private void ToString(StringBuilder sb){var firstInDictionary = true;foreach (var pair in _dictionary){if (!firstInDictionary)sb.Append(",");firstInDictionary = false;var value = pair.Value;var name = pair.Key;if (value is string){sb.AppendFormat("{0}:\"{1}\"", name, value);}else if (value is IDictionary<string, object>){new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);}else if (value is ArrayList){sb.Append(name + ":[");var firstInArray = true;foreach (var arrayValue in (ArrayList)value){if (!firstInArray)sb.Append(",");firstInArray = false;if (arrayValue is IDictionary<string, object>)new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);else if (arrayValue is string)sb.AppendFormat("\"{0}\"", arrayValue);elsesb.AppendFormat("{0}", arrayValue);
}sb.Append("]");}else{sb.AppendFormat("{0}:{1}", name, value);}}sb.Append("}");}
public override bool TryGetMember(GetMemberBinder binder, out object result){if (!_dictionary.TryGetValue(binder.Name, out result)){// return null to avoid exception.  caller can check for null this way...result = null;return true;}
result = WrapResultObject(result);return true;}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result){if (indexes.Length == 1 && indexes[0] != null){if (!_dictionary.TryGetValue(indexes[0].ToString(), out result)){// return null to avoid exception.  caller can check for null this way...result = null;return true;}
result = WrapResultObject(result);return true;}
return base.TryGetIndex(binder, indexes, out result);}
private static object WrapResultObject(object result){var dictionary = result as IDictionary<string, object>;if (dictionary != null)return new DynamicJsonObject(dictionary);
var arrayList = result as ArrayList;if (arrayList != null && arrayList.Count > 0){return arrayList[0] is IDictionary<string, object>? new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x))): new List<object>(arrayList.Cast<object>());}
return result;}}
#endregion}

你可以像这样使用它:

string json = ...;
var serializer = new JavaScriptSerializer();serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
dynamic obj = serializer.Deserialize(json, typeof(object));

所以,给定一个JSON字符串:

{"Items":[{ "Name":"Apple", "Price":12.3 },{ "Name":"Grape", "Price":3.21 }],"Date":"21/11/2010"}

以下代码将在运行时工作:

dynamic data = serializer.Deserialize(json, typeof(object));
data.Date; // "21/11/2010"data.Items.Count; // 2data.Items[0].Name; // "Apple"data.Items[0].Price; // 12.3 (as a decimal)data.Items[1].Name; // "Grape"data.Items[1].Price; // 3.21 (as a decimal)

您想要的DynamicJSONObject对象包含在ASP.NETWeb Pages包的System.Web.Helpers.dll中,该包是WebMatrix的一部分。

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]); // 42string json = writer.Write(output);Console.WriteLine(json); // {"foo":true,"array":[42,false,"Hello!",null]}

有一个名为SimpleJson开发环境的C#轻量级JSON库。

它支持。NET 3.5+、Silverlight和Windows Phone 7。

它支持动态的。NET 4.0

它也可以安装为NuGet包

Install-Package SimpleJson

我做了一个使用扩展对象的新版本的DynamicJsonConver,我使用了扩展对象,因为我想使用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) })); }}}}

. NET 4.0有一个内置库来执行此操作:

using System.Web.Script.Serialization;JavaScriptSerializer jss = new JavaScriptSerializer();var d = jss.Deserialize<dynamic>(str);

这是最简单的方法。

您可以扩展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;}}

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

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 Smithvar age = (int)value.Age;      // 42
var address = value.Address;var city = (string)address.City;   // New Yorkvar state = (string)address.State; // NY

使用Json.NET非常简单:

dynamic stuff = JsonConvert.DeserializeObject("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
string name = stuff.Name;string address = stuff.Address.City;

还有using Newtonsoft.Json.Linq

dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
string name = stuff.Name;string address = stuff.Address.City;

文档:动态查询JSON

您可以使用系统。网络。助手。Json执行此操作-它的Decode方法返回一个动态对象,您可以根据需要遍历该对象。

它包含在System. Web. Helpers程序集(. NET 4.0)中。

var dynamicObject = Json.Decode(jsonString);

简单的“字符串JSON数据”对象没有任何第三方DLL文件:

WebClient client = new WebClient();string getString = client.DownloadString("https://graph.facebook.com/zuck");
JavaScriptSerializer serializer = new JavaScriptSerializer();dynamic item = serializer.Deserialize<object>(getString);string name = item["name"];
//note: JavaScriptSerializer in this namespaces//System.Web.Script.Serialization.JavaScriptSerializer

注意:您也可以使用自定义对象。

Personel item = serializer.Deserialize<Personel>(getString);

最简单的方法是:

包括这个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.

另一种使用牛顿软件包的方法:

dynamic stuff = Newtonsoft.Json.JsonConvert.DeserializeObject("{ color: 'red', value: 5 }");string color = stuff.color;int value = stuff.value;

看看我在CodeProject上写的文章,它准确地回答了这个问题:

具有JSON.NET的动态类型

在这里重新发布的内容太多了,甚至更少,因为那篇文章有一个带有密钥/所需源文件的附件。

将DataSet(C#)与JavaScript一起使用。一个使用DataSet输入创建JSON流的简单函数。创建JSON内容,如(多表数据集):

[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]

只是客户端,使用val。例如,

var d = eval('[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]')

然后使用:

d[0][0].a // out 1 from table 0 row 0
d[1][1].b // out 59 from table 1 row 1
// Created by Behnam Mohammadi And Saeed Ahmadianpublic string jsonMini(DataSet ds){int t = 0, r = 0, c = 0;string stream = "[";
for (t = 0; t < ds.Tables.Count; t++){stream += "[";for (r = 0; r < ds.Tables[t].Rows.Count; r++){stream += "{";for (c = 0; c < ds.Tables[t].Columns.Count; c++){stream += ds.Tables[t].Columns[c].ToString() + ":'" +ds.Tables[t].Rows[r][c].ToString() + "',";}if (c>0)stream = stream.Substring(0, stream.Length - 1);stream += "},";}if (r>0)stream = stream.Substring(0, stream.Length - 1);stream += "],";}if (t>0)stream = stream.Substring(0, stream.Length - 1);stream += "];";return stream;}

获取一个ExpandoObject:

using Newtonsoft.Json;using Newtonsoft.Json.Converters;
Container container = JsonConvert.Deserialize<Container>(jsonAsString, new ExpandoObjectConverter());

试试这个:

  var units = new { Name = "Phone", Color= "White" };var jsonResponse = JsonConvert.DeserializeAnonymousType(json, units);

JSON.NET中的反序列化可以使用JObject类进行动态处理,该类包含在该库中。

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());

参见帖子以获取完整示例。

我在我的代码中使用了这样的方法,它工作得很好

using System.Web.Script.Serialization;JavaScriptSerializer oJS = new JavaScriptSerializer();RootObject oRootObject = new RootObject();oRootObject = oJS.Deserialize<RootObject>(Your JSon String);

我使用http://json2csharp.com/来获取表示JSON对象的类。

输入:

{"name":"John","age":31,"city":"New York","Childs":[{"name":"Jim","age":11},{"name":"Tim","age":9}]}

输出:

public class Child{public string name { get; set; }public int age { get; set; }}
public class Person{public string name { get; set; }public int age { get; set; }public string city { get; set; }public List<Child> Childs { get; set; }}

之后,我使用牛顿软件包来填充类:

using Newtonsoft.Json;
namespace GitRepositoryCreator.Common{class JObjects{public static string Get(object p_object){return JsonConvert.SerializeObject(p_object);}internal static T Get<T>(string p_object){return JsonConvert.DeserializeObject<T>(p_object);}}}

你可以这样称呼它:

Person jsonClass = JObjects.Get<Person>(stringJson);
string stringJson = JObjects.Get(jsonClass);

PS:

如果您的JSON变量名不是有效的C#名称(名称以$开头),您可以这样修复:

public class Exception{[JsonProperty(PropertyName = "$id")]public string id { get; set; }public object innerException { get; set; }public string message { get; set; }public string typeName { get; set; }public string typeKey { get; set; }public int errorCode { get; set; }public int eventId { get; set; }}

您可以使用using Newtonsoft.Json

var jRoot =JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(resolvedEvent.Event.Data));

resolvedEvent.Event.Data是我从调用核心事件得到的响应。

另一种选择是"将JSON粘贴为类",这样它就可以快速轻松地反序列化。

  1. 简单地复制整个JSON
  2. 在Visual Studio中:单击编辑粘贴特殊将JSON粘贴为类

这里有一个更好的解释n piccas…'粘贴JSON类'在ASP.NET和Web工具2012.2 RC

如何使用动态和JavaScriptSerializer解析简单的JSON内容

请添加系统。网络。扩展的引用并在顶部添加此命名空间using System.Web.Script.Serialization;

public static void EasyJson(){var jsonText = @"{""some_number"": 108.541,""date_time"": ""2011-04-13T15:34:09Z"",""serial_number"": ""SN1234""}";
var jss = new JavaScriptSerializer();var dict = jss.Deserialize<dynamic>(jsonText);
Console.WriteLine(dict["some_number"]);Console.ReadLine();}

如何使用动态和JavaScriptSerializer解析嵌套和复杂的json

请添加系统。网络。扩展的引用并在顶部添加此命名空间using System.Web.Script.Serialization;

public static void ComplexJson(){var jsonText = @"{""some_number"": 108.541,""date_time"": ""2011-04-13T15:34:09Z"",""serial_number"": ""SN1234"",""more_data"": {""field1"": 1.0,""field2"": ""hello""}}";
var jss = new JavaScriptSerializer();var dict = jss.Deserialize<dynamic>(jsonText);
Console.WriteLine(dict["some_number"]);Console.WriteLine(dict["more_data"]["field2"]);Console.ReadLine();}

使用CinchooETL-一个可用于将JSON解析为动态对象的开源库:

string json = @"{""key1"": [{""action"": ""open"",""timestamp"": ""2018-09-05 20:46:00"",""url"": null,""ip"": ""66.102.6.98""}]}";using (var p = ChoJSONReader.LoadText(json).WithJSONPath("$..key1")){foreach (var rec in p){Console.WriteLine("Action: " + rec.action);Console.WriteLine("Timestamp: " + rec.timestamp);Console.WriteLine("URL: " + rec.url);Console.WriteLine("IP address: " + rec.ip);}}

输出:

Action: openTimestamp: 2018-09-05 20:46:00URL: http://www.google.comIP address: 66.102.6.98

小提琴样本:https://dotnetfiddle.net/S0ehSV

有关更多信息,请访问代码项目文章

声明:我是这个图书馆的作者。

试试这个方法!

JSON示例:

[{"id": 140,"group": 1,"text": "xxx","creation_date": 123456,"created_by": "xxx@gmail.co","tags": ["xxxxx"]}, {"id": 141,"group": 1,"text": "xxxx","creation_date": 123456,"created_by": "xxx@gmail.com","tags": ["xxxxx"]}]

c#代码:

var jsonString = (File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(),"delete_result.json")));var objects = JsonConvert.DeserializeObject<dynamic>(jsonString);foreach(var o in objects){Console.WriteLine($"{o.id.ToString()}");}

您可以在Newtonsoft. Json的帮助下实现这一点。从NuGet安装它,然后:

using Newtonsoft.Json;
dynamic results = JsonConvert.DeserializeObject<dynamic>(YOUR_JSON);

牛顿软件包创建动态对象真的很棒。

//json is your string containing the JSON valuedynamic data = JsonConvert.DeserializeObject<dynamic>(json);

现在您可以像访问常规对象一样访问data对象。这是我们目前拥有的JSON对象作为示例:

{ "ID":123,"Name":"Jack","Numbers":[1, 2, 3] }

这是反序列化后访问它的方式:

data.ID //Retrieve the intdata.Name //Retrieve the stringdata.Numbers[0] //Retrieve the first element in the array

我想在单元测试中以编程方式执行此操作,我确实可以将其打印出来。

我的解决方案是:

var dict = JsonConvert.DeserializeObject<ExpandoObject>(json) as IDictionary<string, object>;

现在我可以断言

dict.ContainsKey("ExpectedProperty");

如果您想在反序列化JSON时跳过创建类,您可以使用NewtonSoft. Json//牛顿软体序列化匿名类型方法来完成。

下面的示例甚至可以将JSON反序列化为列表的匿名对象。

var json = System.IO.File.ReadAllText(@"C:\TestJSONFiles\yourJSONFile.json");var fooDefinition = new { a = "", b = 0 }; // type with fields of string, intvar fooListDefinition = Enumerable.Range(0, 0).Select(e => fooDefinition).ToList();
var foos = JsonConvert.DeserializeAnonymousType(json, fooListDefinition);

我来这里是为了找到. NET Core的答案,没有任何第三方或其他引用。如果您将ExpandoObject与标准JsonSerializer类一起使用,它可以正常工作。这是对我有效的示例:

using System.Text.Json;using System.Dynamic;
dynamic json = JsonSerializer.Deserialize<ExpandoObject>(jsonText);Console.WriteLine(json.name);

这段代码打印出name属性的字符串值,该属性存在于传递给Deserialize方法的JSON文本中。瞧-没有额外的库,什么都没有。只是。NET核心。

编辑:使用嵌套元素的几个级别的json可能存在问题。适用于单级平面对象。

我需要的是返回一个具有不同字段的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表

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

我真的很喜欢System. Web. Helpers

dynamic data = Json.Decode(json);

因为它支持像

var val = data.Members.NumberTen;

var val data.Members["10"];

对System.Web.Helpers.DLL的引用真的很疯狂,它甚至对控制台和桌面应用程序都不友好。这是我试图直接从中提取与独立文件相同的功能https://github.com/mono/aspnetwebstack/tree/master/src/System.Web.Helpers(仅供参考)

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.using System.Collections.Generic;using System.Diagnostics;using System.Diagnostics.CodeAnalysis;using System.Dynamic;using System.Linq.Expressions;using System.Runtime.CompilerServices;using Microsoft.CSharp.RuntimeBinder;using System.Web.Script.Serialization;using System.IO;using System.Collections;using System.Linq;using System.Globalization;
namespace System.Web.Helpers{public static class Json{private static readonly JavaScriptSerializer _serializer = CreateSerializer();
public static string Encode(object value){// Serialize our dynamic array type as an arrayDynamicJsonArray jsonArray = value as DynamicJsonArray;if (jsonArray != null){return _serializer.Serialize((object[])jsonArray);}
return _serializer.Serialize(value);}
public static void Write(object value, TextWriter writer){writer.Write(_serializer.Serialize(value));}
public static dynamic Decode(string value){return WrapObject(_serializer.DeserializeObject(value));}
public static dynamic Decode(string value, Type targetType){return WrapObject(_serializer.Deserialize(value, targetType));}
public static T Decode<T>(string value){return _serializer.Deserialize<T>(value);}
private static JavaScriptSerializer CreateSerializer(){JavaScriptSerializer serializer = new JavaScriptSerializer();serializer.RegisterConverters(new[] { new DynamicJavaScriptConverter() });return serializer;}internal class DynamicJavaScriptConverter : JavaScriptConverter{public override IEnumerable<Type> SupportedTypes{get{yield return typeof(IDynamicMetaObjectProvider);yield return typeof(DynamicObject);}}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer){throw new NotSupportedException();}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer){Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);IEnumerable<string> memberNames = DynamicHelper.GetMemberNames(obj);foreach (string item in memberNames){dictionary[item] = DynamicHelper.GetMemberValue(obj, item);}
return dictionary;}}internal static dynamic WrapObject(object value){// The JavaScriptSerializer returns IDictionary<string, object> for objects// and object[] for arrays, so we wrap those in different dynamic objects// so we can access the object graph using dynamicvar dictionaryValues = value as IDictionary<string, object>;if (dictionaryValues != null){return new DynamicJsonObject(dictionaryValues);}
var arrayValues = value as object[];if (arrayValues != null){return new DynamicJsonArray(arrayValues);}
return value;}
}// REVIEW: Consider implementing ICustomTypeDescriptor and IDictionary<string, object>public class DynamicJsonObject : DynamicObject{private readonly IDictionary<string, object> _values;
public DynamicJsonObject(IDictionary<string, object> values){Debug.Assert(values != null);_values = values.ToDictionary(p => p.Key, p => Json.WrapObject(p.Value),StringComparer.OrdinalIgnoreCase);}
public override bool TryConvert(ConvertBinder binder, out object result){result = null;if (binder.Type.IsAssignableFrom(_values.GetType())){result = _values;}else{throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "HelpersResources.Json_UnableToConvertType", binder.Type));}return true;}
public override bool TryGetMember(GetMemberBinder binder, out object result){result = GetValue(binder.Name);return true;}
public override bool TrySetMember(SetMemberBinder binder, object value){_values[binder.Name] = Json.WrapObject(value);return true;}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value){string key = GetKey(indexes);if (!String.IsNullOrEmpty(key)){_values[key] = Json.WrapObject(value);}return true;}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result){string key = GetKey(indexes);result = null;if (!String.IsNullOrEmpty(key)){result = GetValue(key);}return true;}
private static string GetKey(object[] indexes){if (indexes.Length == 1){return (string)indexes[0];}// REVIEW: Should this throw?return null;}
public override IEnumerable<string> GetDynamicMemberNames(){return _values.Keys;}
private object GetValue(string name){object result;if (_values.TryGetValue(name, out result)){return result;}return null;}}[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "This class isn't meant to be used directly")]public class DynamicJsonArray : DynamicObject, IEnumerable<object>{private readonly object[] _arrayValues;
public DynamicJsonArray(object[] arrayValues){Debug.Assert(arrayValues != null);_arrayValues = arrayValues.Select(Json.WrapObject).ToArray();}
public int Length{get { return _arrayValues.Length; }}
public dynamic this[int index]{get { return _arrayValues[index]; }set { _arrayValues[index] = Json.WrapObject(value); }}
public override bool TryConvert(ConvertBinder binder, out object result){if (_arrayValues.GetType().IsAssignableFrom(binder.Type)){result = _arrayValues;return true;}return base.TryConvert(binder, out result);}
public override bool TryGetMember(GetMemberBinder binder, out object result){// Testing for members should never throw. This is important when dealing with// services that return different json results. Testing for a member shouldn't throw,// it should just return null (or undefined)result = null;return true;}
public IEnumerator GetEnumerator(){return _arrayValues.GetEnumerator();}
private IEnumerable<object> GetEnumerable(){return _arrayValues.AsEnumerable();}
IEnumerator<object> IEnumerable<object>.GetEnumerator(){return GetEnumerable().GetEnumerator();}
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]public static implicit operator object[](DynamicJsonArray obj){return obj._arrayValues;}
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]public static implicit operator Array(DynamicJsonArray obj){return obj._arrayValues;}}
/// <summary>/// Helper to evaluate different method on dynamic objects/// </summary>public static class DynamicHelper{// We must pass in "object" instead of "dynamic" for the target dynamic object because if we use dynamic, the compiler will// convert the call to this helper into a dynamic expression, even though we don't need it to be.  Since this class is internal,// it cannot be accessed from a dynamic expression and thus we get errors.
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for detailspublic static bool TryGetMemberValue(object obj, string memberName, out object result){try{result = GetMemberValue(obj, memberName);return true;}catch (RuntimeBinderException){}catch (RuntimeBinderInternalCompilerException){}
// We catch the C# specific runtime binder exceptions since we're using the C# binder in this caseresult = null;return false;}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to swallow exceptions that happen during runtime binding")]public static bool TryGetMemberValue(object obj, GetMemberBinder binder, out object result){try{// VB us an instance of GetBinderAdapter that does not implement FallbackGetMemeber. This causes lookup of property expressions on dynamic objects to fail.// Since all types are private to the assembly, we assume that as long as they belong to CSharp runtime, it is the right one.if (typeof(Binder).Assembly.Equals(binder.GetType().Assembly)){// Only use the binder if its a C# binder.result = GetMemberValue(obj, binder);}else{result = GetMemberValue(obj, binder.Name);}return true;}catch{result = null;return false;}}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for detailspublic static object GetMemberValue(object obj, string memberName){var callSite = GetMemberAccessCallSite(memberName);return callSite.Target(callSite, obj);}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for detailspublic static object GetMemberValue(object obj, GetMemberBinder binder){var callSite = GetMemberAccessCallSite(binder);return callSite.Target(callSite, obj);}
// dynamic d = new object();// object s = d.Name;// The following code gets generated for this expression:// callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Name", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));// callSite.Target(callSite, d);// typeof(Program) is the containing type of the dynamic operation.// Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for detailspublic static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(string memberName){var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, typeof(DynamicHelper), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });return GetMemberAccessCallSite(binder);}
// Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for detailspublic static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(CallSiteBinder binder){return CallSite<Func<CallSite, object, object>>.Create(binder);}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for detailspublic static IEnumerable<string> GetMemberNames(object obj){var provider = obj as IDynamicMetaObjectProvider;Debug.Assert(provider != null, "obj doesn't implement IDynamicMetaObjectProvider");
Expression parameter = Expression.Parameter(typeof(object));return provider.GetMetaObject(parameter).GetDynamicMemberNames();}}
}