NET 4.0 动态JSON解析器

简介

其实已经有许多用来解析JSON格式数据的库了,为什么我们还想要再创造一个呢?

因为.NET 4.0框架引入了一个新的类型:dynamic!

背景

dynamic实际上是一个静态类型,但是编译器看待它与其它的类型不同。编译器遇到dynamic类型时不会作任何的类型安全检查(绕过了静态类型检查)

例如:

01class Program
02{
03    static void Main(string[] args)
04    {
05        func(1); // 'int' does not contain a definition for 'error'
06    }
07    static void func(dynamic obj)
08    {
09        obj.error = "oops";
10    }
11}

上面这程序调用带有一个int型变量的func函数,当然,int类型没有一个名为error属性,但是程序在编译时不会产生任何错误。而一切在运行时便看起来有所不同了。会抛出出错信息为'int'不包含'error'的定义的RuntimeBinderException异常。

DynamicObject

加入了dynamic功能的.NET层叫做Dynamic Language Runtime(DLR)。DLR处于Common Language Runtime(CLR)的顶部。动态对象都实现了IDynamicMetaObjectProvider接口。

DynamicObject是一个实现了IDynamicMetaObjectProvider的抽象类并提供一系列的基本操作。继承自DynamicObject的一个类可以重载例如TrySetMember以及TryGetMember方法来set和get属性。

以下是DynamicObject几个比较重要的可重载的成员函数,以实现对动态类型的自定义表现。

TryBinaryOperation  - 二进制操作 *,+,-...

TryUnaryOperation  - 一元操作 --,++,...

TryGetIndex  - 以索引访问一个对象操作 []

TrySetIndex  - 以索引设置一个对象操作 []

TryGetMember  - 获取一个属性值,例如:obj.property_name

TrySetMember  - 设置一个属性值,例如:obj.property_name = "value"

TryInvokeMember  - 调用一个方法,例如:obj.SomeMethod(...)

以下是一个实现了所有上述方法的例子:

001public class DynamicConsoleWriter : DynamicObject
002{
003    protected string first = "";
004    protected string last  = "";
005    public int Count
006    {
007        get
008        {
009            return 2;
010        }
011    }
012    public override bool TryBinaryOperation(BinaryOperationBinder binder, 
013                         object arg, out object result)
014    {
015        bool success = false;
016        if (binder.Operation == System.Linq.Expressions.ExpressionType.Add)
017        {
018            Console.WriteLine("I have to think about that");
019            success = true;
020        }
021        result = this;
022        return success;
023    }
024    public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result)
025    {
026        bool success = false;
027        if (binder.Operation == System.Linq.Expressions.ExpressionType.Increment)
028        {
029            Console.WriteLine("I will do it later");
030            success = true;
031        }
032        result = this;
033        return success;
034    }
035    public override bool TryGetIndex(GetIndexBinder binder, 
036                    object[] indexes, out object result)
037    {
038        result = null;
039        if ( (int)indexes[0] == 0)
040        {
041            result = first;
042        }
043        else if ((int)indexes[0] == 1)
044        {
045            result = last;
046        }
047        return true;
048    }
049    public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
050    {
051        if ((int)indexes[0] == 0)
052        {
053            first = (string)value;
054        }
055        else if ((int)indexes[0] == 1)
056        {
057            last = (string)value;
058        }
059        return true;
060    }
061    public override bool TryGetMember(GetMemberBinder binder, out object result)
062    {
063        string name    = binder.Name.ToLower();
064        bool   success = false;
065        result = null;
066        if (name == "last")
067        {
068            result = last;
069            success = true;
070        }
071        else if (name == "first")
072        {
073            result = first;
074            success = true;
075        }
076        return success;
077    }
078    public override bool TrySetMember(SetMemberBinder binder, object value)
079    {
080        string name    = binder.Name.ToLower();
081        bool   success = false;
082        if (name == "last")
083        {
084            last = (string)value;
085            success = true;
086        }
087        else if (name == "first")
088        {
089            first = (string)value;
090            success = true;
091        }
092        return success;
093    }
094    public override bool TryInvokeMember(InvokeMemberBinder binder, 
095                    object[] args, out object result)
096    {
097        string name = binder.Name.ToLower();
098        bool success = false;
099        result = true;
100        if (name == "writelast")
101        {
102            Console.WriteLine(last);
103            success = true;
104        }
105        else if (name == "writefirst")
106        {
107            Console.WriteLine(first);
108            success = true;
109        }
110        return success;
111    }
112}

以下展示了我们如何使用它们:

01dynamic dynamicConsoleWriter = new DynamicConsoleWriter();
02dynamicConsoleWriter.First = "I am just a"; // TrySetMember is invoked
03dynamicConsoleWriter.Last = " Lion!";       // TrySetMember is invoked 
04  
05var result1 = dynamicConsoleWriter + 2;     // TryBinaryOperation is invoked
06var result2 = ++dynamicConsoleWriter;       // TryUnaryOperation is invoked
07dynamicConsoleWriter[0] = "Hello";          // TrySetIndex is invoked
08var result3 = dynamicConsoleWriter[0];      // TryGetIndex is invoked
09var result4 = dynamicConsoleWriter.First;   // TryBinaryOperation is invoked
10var result5 = dynamicConsoleWriter.Last;    // TryBinaryOperation is invoked 
11var result6 = dynamicConsoleWriter.Count;   // DynamicConsoleWriter Count property is called
12  
13dynamicConsoleWriter.WriteFirst();          // TryInvokeMember is invoked
14dynamicConsoleWriter.WriteLast();           // TryInvokeMember is invoked

另外一个动态类型很酷的特性就是他们实现了专一性,也就是说,大部分特定的函数调用在运行时将会被选择。

当遇到类型找不到时将会抛出RuntimeBinderException异常。该异常可通过实现一个接受object值的函数来避免。

01public class Specificity
02{
03    public static void printDynamic(dynamic obj)
04    {
05        print(obj);
06    }
07    protected static void print(List<int> list)
08    {
09        foreach (var item in list)
10        {
11            Console.WriteLine(item);
12        }
13    }
14    protected static void print(object obj)
15    {
16        Console.WriteLine("I do not know how to print you");
17    }
18}

当我们传递任何参数至printDynamic函数除了List<int>时,print(object obj)将会被调用。

动态JSON转换器

JavaScriptSerializer将会把一个JSON字符串转换至一个IDictionary<string,object>中。

JavaScriptSerializer在System.Web.Extensions中声明,使用System.Web.Script.Serialization来编译代码。

1var serializer = new JavaScriptSerializer();
2serializer.RegisterConverters(new[] { new DynamicJsonConverter() }); 
3dynamic data = serializer.Deserialize<object>(json);

serializer。Deserialize<object>(json)转换JSON字符串并调用JavaScriptConverter的Deserialize方法,我们重载此方法来从Deserialize方法中提供的dictionary创建新的DynamicJsonObjec。

DynamicObject如魔法搬将一个dictionary转换为包含所有JSON属性的对象。

ExpandoObject是一个新类但却是不是我们需要的,它提供的无法满足我们更加灵活的需求。

每个序列化的dictionary中的值是一个简单类型(也就是int,string,double),IDictionary<string,object>({...})或者ArrayList。

我们重载了DynamicObject的TryGetMember函数来处理所有这三种类型的序列化dictionary值。

同样我们也会实现TrySetMember方法以添加新的域到JSON对象中,并且将实现IEnumerable接口来实现对动态JSON对象的简单迭代。

以下便是如何使用动态解析器的例子:

01const string json =
02    "{" +
03    "     \"firstName\": \"John\"," +
04    "     \"lastName\" : \"Smith\"," +
05    "     \"age\"      : 25," +
06    "     \"address\"  :" +
07    "     {" +
08    "         \"streetAddress\": \"21 2nd Street\"," +
09    "         \"city\"         : \"New York\"," +
10    "         \"state\"        : \"NY\"," +
11    "         \"postalCode\"   : \"11229\"" +
12    "     }," +
13    "     \"phoneNumber\":" +
14    "     [" +
15    "         {" +
16    "           \"type\"  : \"home\"," +
17    "           \"number\": \"212 555-1234\"" +
18    "         }," +
19    "         {" +
20    "           \"type\"  : \"fax\"," +
21    "           \"number\": \"646 555-4567\"" +
22    "         }" +
23    "     ]" +
24    " }";
25  
26var serializer = new JavaScriptSerializer();
27serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
28dynamic data = serializer.Deserialize<object>(json);
29Console.WriteLine(data.firstName);           // John
30Console.WriteLine(data.lastName);            // Smith
31Console.WriteLine(data.age);                 // 25
32Console.WriteLine(data.address.postalCode);  // 11229
33Console.WriteLine(data.phoneNumber.Count);   // 2
34Console.WriteLine(data.phoneNumber[0].type); // home
35Console.WriteLine(data.phoneNumber[1].type); // fax
36foreach (var pn in data.phoneNumber)
37{
38    Console.WriteLine(pn.number);            // 212 555-1234, 646 555-4567
39}
40Console.WriteLine(data.ToString());
41  
42// and creating JSON formatted data
43dynamic jdata   = new DynamicJsonObject();
44dynamic item1   = new DynamicJsonObject();
45dynamic item2   = new DynamicJsonObject();
46ArrayList items = new ArrayList();
47item1.Name  = "Drone";
48item1.Price = 92000.3;
49item2.Name  = "Jet";
50item2.Price = 19000000.99;
51items.Add(item1);
52items.Add(item2);
53jdata.Date  = "06/06/2004";
54jdata.Items = items;
55Console.WriteLine(jdata.ToString());

鸣谢

初始化动态JSON转换器是由Shawn Weisfeld编写

License

此文章涉及到的任何源代码以及文件都在The Code Project Open License (CPOL)证书公开

via:codeproject.com  OSChina原创编译

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Json.NET 描述: json。 网络是一个流行的高性能JSON为。NET框架 灵活的JSON序列化器对之间的转换。净对象和JSON linq到JSON用于手动阅读和写作JSON 高性能,速度比。净的内置JSON序列化器 写缩进,容易阅读JSON JSON和XML之间进行转换 支持: .NET 2, .NET 3.5, .NET 4, .NET 4.5, Silverlight, Windows Phone and Windows 8 Store 版本: Json.NET has different libaries for the various .NET Framework versions. -Net45: .NET latest (4.5) -Net40: .NET 4.0 -Net35: .NET 3.5 -Net20: .NET 2.0 -WinRT: Windows 8 Store -Portable45: .NET 4.5, Windows Phone 8, Windows 8 Store -Portable40: .NET 4.0, Windows Phone 7, Windows 8 Store, Silverlight 4 Notes: Microsoft stopped support for the Compact Framework in Visual Studio 2010. For a Compact Framework 3.5 build download Json.NET 3.5. For a Silverlight 3.0 build download Json.NET 3.5. Microsoft Visual Studio 2010 重新生成解决方案的一些警告处理 警告 2 预定义类型“System.Action”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 警告 3 预定义类型“System.Action”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 警告 4 预定义类型“System.Action”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 警告 5 预定义类型“System.Action”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 警告 6 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 警告 7 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 警告 8 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 警告 9 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 警告 10 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework \v4.0\mscorlib.dll”中的定义 ClassLibrary1 问题原因:检查程序发现,由于项目中引用了Newtonsoft.Json.Net20,从而造成系统的类重名(项目FRAMEWORK的版本4.0)。 Newtonsoft.Json.Net 包括: .NET 2, .NET 3.5, .NET 4, .NET 4.5, Silverlight, Windows Phone and Windows 8 Store,所有dll文件和源码,有需要的同学可以直接下载。 个人网站多多支持:www.mlyuansu.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值