在玩转动态编译:一、初识中,我们已经学会了最简单的使用动态编译。今天直接由实战入手,看看真实情况下的动态编译能为我们来带什么。
今天要演示的实例是一个在实际开发中经常遇到的情况,对象转Json。
我将会使用2种方式分别做一个转json字符串的实例,1:反射;2:动态编译
- 分析问题
分析C#对象在json中的映射。总体来说json对象只有几种情况
- 键值对对象,由多组键对象+值对象构成,最外面是一对花括号包裹,键值对对象同时也可作为“值对象”使用
- 数组对象,由多个值对象构成,最外面是一对中括号包裹,数组对象同时也可作为“值对象”使用
- 键对象,由一个字符串构成,在键值对对象组成中担任“键”
- 一般值对象,由一个单独的值构成,可以是string,int,bool等,在键值对对象或者数组对象中担任“值”
- 特殊值对象,键值对对象或数组对象,本身也可以作为值对象使用
这4中对象分别对应了C#中的:
键值对对象 -> 任何有公开属性的对象,或者实现了IDictionary的对象,或者同时拥有Key和Value枚举的对象
数组对象 -> 实现了IEnumerator或者IEnumerable接口的对象
键对象 -> string对象
一般值对象 -> System命名空间下的简单值类型,包括int,bool,float,DateTime等,外加一个string
- 编写基类
为了满足所有类型的转换需求,首先要建立一个抽象基类JsonConverter
JsonConverter View Code
这个类完成大部分基础类型的转换工作,只有一个方法等待实现
- 反射实现
JsonConverter_Reflection View Code
- 动态编译实现
动态编译的逻辑是这样的:因为在程序运行中,每个类型的相对应属性不可能发生更变,所以可以针对每个类型生成一个方法,
比如User对象
class User { public string Name { get; set; } public int Age { get; set; } public bool Sex { get; set; } }
我们可以为User对象生成一个方法,例如这个
public static string ToJson(User user) { return "{ \"Name\":\"" + user.Name + "\",\"Age\":" + user.Age + ",\"Sex\",\"" + (user.Sex ? "男" : "女") + "\"}"; }
这个方法如果自己写实在是太蛋疼了,但是我们可以在程序中构造,由于动态编译来完成,然后把方法委托缓存起来,下次就可以直接使用了
整个方法是这样的
JsonConverter_Dyncmp View Code
- 测试调用
namespace blqw { public static class Json { public static JsonConverter Converter1 = new JsonConverter_Reflection(); public static JsonConverter Converter2 = new JsonConverter_Dyncmp(); public static string ToJson_1(object obj) { return Converter1.ToJson(obj); } public static string ToJson_2(object obj) { return Converter2.ToJson(obj); } } }
ToJson_1就是反射方式
ToJson_2是动态编译的方式
再附上测试代码
一个非常复杂的对象
User View Code
static User GetUser() {//这里我尽量构造一个看上去很复杂的对象,并且这个对象几乎涵盖了所有常用的类型 User user = new User(); user.UID = Guid.NewGuid(); user.Birthday = new DateTime(1986, 10, 29, 18, 00, 00); user.IsDeleted = false; user.Name = "blqw"; user.Sex = UserSex.Male; user.LoginHistory = new List<DateTime>(); user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(8, 00, 00))); user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(10, 10, 10))); user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(12, 33, 56))); user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(17, 25, 18))); user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(23, 06, 59))); user.Info = new UserInfo(); user.Info.Address = "广东省广州市"; user.Info.ZipCode = 510000; user.Info.Phone = new Dictionary<string, string>(); user.Info.Phone.Add("手机", "18688888888"); user.Info.Phone.Add("电话", "82580000"); user.Info.Phone.Add("短号", "10086"); user.Info.Phone.Add("QQ", "21979018"); return user; }
测试用代码:
static void Main(string[] args) { var = GetUser();
Stopwatch sw = new Stopwatch(); sw.Restart(); for (int i = 0; i < 10000; i++) { Json.ToJson_1(user); } sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds + "ms"); sw.Restart(); for (int i = 0; i < 10000; i++) { Json.ToJson_2(user); } sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds + "ms"); Console.WriteLine(); Console.WriteLine(Json.ToJson_1(user)); Console.WriteLine(); Console.WriteLine(Json.ToJson_2(user)); }
- 查看结果
- 小结
看到结论,可能有人要开始说了:貌似第二个动态编译的方法性能还不如反射的好啊~~
目前的情况来看呢,确实是这样的.不过动态编译当然不止如此,
性能上的问题是一定要解决的
欲知后事如何,且听下回分解