Fork me on GitHub
动态编译
 


玩转动态编译:一、初识中,我们已经学会了最简单的使用动态编译。今天直接由实战入手,看看真实情况下的动态编译能为我们来带什么。

今天要演示的实例是一个在实际开发中经常遇到的情况,对象转Json。

我将会使用2种方式分别做一个转json字符串的实例,1:反射;2:动态编译

  • 分析问题

 分析C#对象在json中的映射。总体来说json对象只有几种情况

  1. 键值对对象,由多组键对象+值对象构成,最外面是一对花括号包裹,键值对对象同时也可作为“值对象”使用
  2. 数组对象,由多个值对象构成,最外面是一对中括号包裹,数组对象同时也可作为“值对象”使用
  3. 键对象,由一个字符串构成,在键值对对象组成中担任“键”
  4. 一般值对象,由一个单独的值构成,可以是string,int,bool等,在键值对对象或者数组对象中担任“值”
  5. 特殊值对象,键值对对象或数组对象,本身也可以作为值对象使用

这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));
}
复制代码

 

 

  • 查看结果

  • 小结
看到结论,可能有人要开始说了:貌似第二个动态编译的方法性能还不如反射的好啊~~
目前的情况来看呢,确实是这样的.不过动态编译当然不止如此,
性能上的问题是一定要解决的

欲知后事如何,且听下回分解

posted on 2013-08-08 10:57  HackerVirus  阅读(167)  评论(0编辑  收藏  举报