利用FastReflectionLib快速实现对象克隆

一、两个相同类型对象属性快速赋值(快速实现对象克隆)

有时候我们会构造一个实例a并赋值,然后new一个对象b并将a对象的属性完全赋值给b(不完全是所谓的深克隆?)。这个功能是开发中比较常用的,我记得几年前学.net remoting编程的时候写了很多代码实现过类似的转换。

实现这种对象克隆的最简单的方法就是属性一一对应并赋值。这样实现的好处是性能较高(和下面介绍的两个方法比较),不好的地方也显而易见:如果属性较多,则代码量相当可观;如果类的属性添加或者减少,则赋值部分的代码必然发生改动。

实现属性动态赋值,最简单的方式当然是通过反射(或者emit的方式):

ReflectClone        /// <summary>
        /// 对象克隆
        /// </summary>
        /// <param name="source">原始对象</param>
        /// <param name="dest">目标对象</param>
        public static void ReflectClone(object source, object dest)
        {
            PropertyInfo[] properties = source.GetType().GetProperties();
            foreach (PropertyInfo item in properties)
            {
                PropertyInfo property = dest.GetType().GetProperty(item.Name);
                try
                {
                    property.SetValue(dest, item.GetValue(source, null), null);
                }
                catch
                {
                }
            }
        }

 

但是众所周知,反射会有一定的性能问题,所以,有牛人做了个快速反射类库,而且调用也很简洁:

FastClone        /// <summary>
        /// 对象克隆
        /// </summary>
        /// <param name="source">原始对象</param>
        /// <param name="dest">目标对象</param>
        public static void FastClone(object source, object dest)
        {
            PropertyInfo[] properties = source.GetType().GetProperties();
            foreach (PropertyInfo item in properties)
            {
                PropertyInfo property = dest.GetType().GetProperty(item.Name);
                try
                {
                    property.FastSetValue(dest, item.FastGetValue(source));
                }
                catch
                {
                }
            }
        }

 

调用如下:

DeepCloneTest        private static void Test()
        {
            Person original = new Person
                                  {
                                      Id = 1024,
                                      Name = "jeffwong",
                                      Persons = new List<Person>
                                                    {
                                                        new Person
                                                            {
                                                                Id = 1023,
                                                                Name = "jeff",
                                                                Persons = new List<Person>
                                                                              {
                                                                                  new Person
                                                                                      {
                                                                                          Id = 1023,
                                                                                          Name = "jeff",
                                                                                      }
                                                                              }
                                                            }
                                                    }
                                  };

            Person target = new Person();
            //ReflectClone(original, target);
            //Console.WriteLine(target.Persons.Count);

            FastClone(original, target);
            Console.WriteLine(target.Persons.Count);
        }

 

当然,上面两个方法您还可以改进成通用泛型方法来调用。经循环10000次测试,性能提升确实可观。快速反射类库的应用远不止于此简单小功能的实现,在自己DIY开发的ORM中我已经开始大量使用,而且线程安全,实际使用效果很不错,感谢FastReflectionLib作者老赵

By the way,今天coding的时候又碰到要实现这种功能,问了一下同事,他们提供的方法也类似于上面提到的方法,所以回来之后补记一下,希望可以对你也有所帮助。

 

二、扩展方法

1、两个简单的字符串扩展方法

(1)、字符串包含(Contains)方法的扩展

首先通过一段代码看一下原生Contains方法的简单测试结果:

   string str = "www.cnblogs.com 博客园(cnblogs)的技术氛围真好啊!";
            string strNull = null;
            string strEmpty = string.Empty;
            //Console.WriteLine(str.Contains(strNull));//throw ArgumentNullException
            if (strEmpty!=null)
            {
                Console.WriteLine(str.Contains(strEmpty));//true
            }
            Console.WriteLine(str.Contains(""));//true
            Console.WriteLine(str.Contains("cnblogs"));//true

我们可以看到,字符串的Contains方法的作用是返回一个值,该值指示指定的 System.String 对象是否出现在此字符串中。对于输入的参数value,如果是null,直接抛出ArgumentNullException异常。对于我们平时使用者来说,这一点感觉非常不方便,因为每次调用contains方法都必须进行非空(null)判断和处理。我们常规的认知是一个实实在在的字符串,如果要在其内找到一个空引用(null)的字符串(没有分配内存难道不是不存在?),毫无疑问是找不到的,应该直接返回true才对。同时还有一个地方也要注意,在返回结果中,如果 value 参数为空字符串 ("",也就是string.Empty),只要某字符串不是null,对于value为string.Empty或者“”的情况,调用Contains方法都是返回true。但是我们通常认为,如果一个实实在在含有内容的字符串(哪怕内容是空格“ ”),怎么能包含空(“”或者string.Empty)呢?

当然有一种情况例外,就是除非这个字符串自身就是空(“”或者string.Empty),这时候Contains“”或者string.Empty应该返回为true。

下面我们可以按照自己的要求改进一下这个包含关系,做出如下的IsContains扩展,以后调用的时候,可以省却很多判断,而且符合我们的常规认知:

StringExtensionpublic static class StringExtension
{
    public static bool IsContains(this string self, string value)
    {
        if (value == null)
        {
            return false;
        }
        if (value.Length == 0) //string.Empty
        {
            return self.Length == value.Length;
        }
        return self.Contains(value);
    }
}

相应的测试如下:

 string str = "www.cnblogs.com 博客园(cnblogs)的技术氛围真好啊!";
            string strNull = null;
            string strEmpty = string.Empty;
            Console.WriteLine(str.IsContains(strNull));//false
            Console.WriteLine(str.IsContains(strEmpty));//false
            Console.WriteLine(str.IsContains(""));//false

            Console.WriteLine(str.IsContains("cnblogs"));//true
            Console.WriteLine(strEmpty.IsContains(strEmpty));//true
            Console.WriteLine("".IsContains(strEmpty));//true
            Console.WriteLine("".IsContains(""));//true

(2)、IsNullOrWhiteSpace方法

在c#4.0中,微软已经将这个静态方法添加到类库中(我测试效果的时候,发现对于“”和string.Empty,它们返回的结果都是true)。这个方法和字符串的IsNullOrEmpty形式上比较相似,现在大家看到名称一眼就知道这个方法有什么用。但是在c#4.0之前,我们判断字符串是否为null或者空格,都要写一个字符串帮助类处理一下,虽然很简单,这里也把它写成扩展方法:

StringExtension    public static bool IsNullOrWhiteSpace(this string self)
    {
        if (self==null)
        {
            return true;
        }
        return self.Trim().Length == 0;
    }

 

调用代码如下:

 string str = "博客写得很简单很随意,如果牛人来指点一下,真是增色不少啊";
            Console.WriteLine(str.IsNullOrWhiteSpace());//false
            //Console.WriteLine(string.IsNullOrWhiteSpace(str));// false
            str = "   ";
            //Console.WriteLine(string.IsNullOrWhiteSpace(str));// true
            Console.WriteLine(str.IsNullOrWhiteSpace());//true
           
            str=null;
            Console.WriteLine(str.IsNullOrWhiteSpace());//true
           
            str = "";
            Console.WriteLine(str.IsNullOrWhiteSpace());//true
            //Console.WriteLine(string.IsNullOrWhiteSpace(str));// true
            
            str = string.Empty;
            Console.WriteLine(str.IsNullOrWhiteSpace());//true

            //Console.WriteLine(string.IsNullOrWhiteSpace(str));// true
            

2、DataTable的扩展方法

DataTable的合并方法,从园子里的看到这一篇博客,恍然大悟,发现DataTable的Merge方法内有乾坤。而且根据我的亲身实践,性能确实如原文所述有点出乎意料,然后花了几分钟把它写成扩展方法:

DataTableExtension public enum MergeType
    {
        Default = 1, 
        ImportRow = 2,
    }

    /// <summary>
    /// DataTable Merge method extension
    /// </summary>
    public static class DataTableExtention
    {
        public static void Merge(this DataTable dt, DataTable table, MergeType mergeType)
        {
            switch (mergeType)
            {
                default:
                case MergeType.Default:
                    dt.Merge(table);
                    break;

                case MergeType.ImportRow:
                    foreach (DataRow item in table.Rows)
                    {
                        dt.ImportRow(item);
                    }
                    break;
            }
        }

        public static void Merge(this DataTable dt, DataRowCollection drc)
        {
            foreach (DataRow item in drc)
            {
                dt.ImportRow(item);
            }
        }

        public static void Merge(this DataTable dt, DataRow[] rows)
        {
            foreach (DataRow item in rows)
            {
                dt.ImportRow(item);
            }
        }
    }

 

园子里鹤冲天对扩展方法的研究很用心也很深入,而且不少实现都很巧妙实用,大家不妨参考一下。

 

三、新浪微博用户创建时间json字符串转换为DateTime

近期对OAuth做了一些浅显的开发调研,发现各个开放平台的资料参差不齐,尤其是对.NET的支持实在不太友好,单纯调通一个简单的小功能都要花费不少时间和精力。相对而言新浪微薄做的更出色,可以参考的开发相关的资料也最多。但是开发调试的时候发现通过新浪微博OAuth登录并获取用户信息时,根据返回的JSON字符串进行实体对象的转换,创建时间(created_at)不能正确转换成为DateTime类型。比如一个用户,通过授权然后登录测试网站以后,网站后台可以获取一些个人注册和微博账号相关信息,新浪微博开放平台返回的json格式字符串包含的创建时间字符串如下:

created_at:Wed May 05 00:00:00 +0800 2010

被微软宠坏了。这种时间格式看着太像javascript获取的时间了,但是仔细对比还真是和javascript生成的不一样(js格式的日期形如:Thu Aug 25 19:40:25 UTC+0800 2011),反正看来看去不如c#中经常使用的datetime标准格式顺眼。

经查,这种写法就是传说中的UTC,后来通过Json一些工具进行转换,发现Json.Net、Jayrock.Json以及简单直接的JsonHelper都无法直接将该字符串正确转换为c#的datetime数据类型。网上搜索了一下,发现可以通过DateTime.ParseExact进行这种时间格式的转换:

     /// <summary>
        /// 按照utc时间字符串格式转换为datetime
        /// </summary>
        /// <param name="strTime"></param>
        /// <returns></returns>
        public static DateTime? ConvertToTime(string strTime)
        {
            DateTime? dt = null;
            try
            {
                //格式形如:Sun Oct 18 00:00:00 +0800 2009
                if (string.IsNullOrEmpty(strTime) == false)
                {
                    dt = DateTime.ParseExact(strTime, "ddd MMM d HH:mm:ss zzz yyyy",
                         CultureInfo.InvariantCulture);
                }
            }
            catch
            {
            }
            return dt;
        }

通过上面的函数转换,我的一个新浪微博账号创建于created_at:2010-05-05。

时间过得飞快。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值