当前位置:编程学习 > C#/ASP.NET >>

最高效率的对象深拷贝通用方法

曾有人发帖要高效的对象拷贝通用方法,当时只给了一个简单类型的拷贝,现在挤出点时间完成了这个功能,内部的引用类型依次深度拷贝。

完整代码见博客:http://blog.csdn.net/qldsrx/article/details/8265985

这里发帖收集建议意见,简单的测试了下,已经非常完美的运行了,目前能支持任何带无参数的构造函数的类的深拷贝,一元数组的深拷贝,数组和类的循环嵌套深拷贝(即父子关系的类,或双向链表)。

感兴趣的朋友,可以研究下Emit部分,这是C#的精华,也是能够提高效率的必备利器,嫌.NET慢的人不要光抱怨,那是因为你们不懂优化代码,会了Emit就可以最高限度的优化代码。


/// <summary>  
/// 创建对象深度复制的副本  
/// </summary>
public static T ToObjectCopy<T>(this T source) where T : class 

/// <summary>  
/// 将source对象的所有属性复制到target对象中,深度复制  
/// </summary> 
public static void ObjectCopyTo<T>(this T source, T target) where T : class

这2个方法原型是给外部调用的,使用起来很方便,也足够了。下面说下一个很常见的使用场合,那就是实体类的复制并修改,当我们要编辑集合中的某个实体对象的内容时,又怕改错了,想提供回滚功能,就可以用它将其复制一个副本出来。

虽然已经改过不少次了,但难免有BUG,欢迎提出宝贵意见。代码中的注释不多,没那么多时间完善,想学习的人可以对照MSDN慢慢看,这东西要消化很费脑细胞,慢慢琢磨吧。 --------------------编程问答-------------------- 先推荐,坐沙发。 --------------------编程问答-------------------- 占位学习
关注.net的性能优化。 --------------------编程问答-------------------- 不过我还是觉得,所谓通用的深拷贝方法,应该是类库自己管理自己产生的对象时候用的。比如orm框架、rpc框架等等。而不应该去掺和用户编写的对象,因为如何正确拷贝对象,是业务逻辑考虑的事情,而不是底层层面的事情。谁写的对象,谁规定怎么拷贝。 --------------------编程问答-------------------- 占楼学习 --------------------编程问答-------------------- 这代码写得挺神。 --------------------编程问答-------------------- 好东西啊,支持一下。 --------------------编程问答-------------------- 我也有改进一个,是根据对象类型生成一个新的对象

使用:
Type type = typeof(ClassName); 
ClassName classObject=(ClassName)CreateInstance.CreateInstanceByExpression(type);
ClassName classObject=(ClassName)Activator.CreateInstance(type);
/// <summary>
    /// 通过表达式目录树构建对象实例(使用缓存) 
    /// .net3.5以上版本支持
    /// </summary>
    public static class CreateInstance
    {
        private static Hashtable paramCache = Hashtable.Synchronized(new Hashtable());//缓存

        /// <summary>
        /// 根据对象类型创建对象实例
        /// </summary>
        /// <param name="key">对象类型</param>
        /// <returns></returns>
        public static object CreateInstanceByExpression(Type key)
        {
            Func<object> value = (Func<object>)paramCache[key];
            if (value == null)
            {
                value = CreateInstanceByType(key);
                paramCache[key] = value;
            }
            return value();
        }

        private static Func<object> CreateInstanceByType(Type type)
        {
            return Expression.Lambda<Func<object>>(Expression.New(type), null).Compile();
        }
    }
--------------------编程问答-------------------- http://blog.csdn.net/zanfeng/article/details/8266840


FastSerialization

 代码太长。。 --------------------编程问答-------------------- --------------------编程问答--------------------     --------------------编程问答-------------------- 刚发现了自己的代码中的一个严重BUG,不支持String类型的拷贝,因为String是特殊的引用类型,又是最常用的引用类型,处理方式几乎和值类型差不多,被我给忽略了。

正在修正中。。。

3楼说的在理,不过我这个是给懒人用的方法,毕竟定义类的时候去写自身的拷贝方法,一来类显得有点臃肿,二来不是自动生成的类会增加工作量,只要我这个方法用起来没任何问题,效率又高,为啥不用呢?选择C#就是为了提高开发效率,自己为每个类写拷贝方法,编程效率就降低了。 --------------------编程问答--------------------
引用 11 楼 qldsrx 的回复:
刚发现了自己的代码中的一个严重BUG,不支持String类型的拷贝,因为String是特殊的引用类型,又是最常用的引用类型,处理方式几乎和值类型差不多,被我给忽略了。

正在修正中。。。

3楼说的在理,不过我这个是给懒人用的方法,毕竟定义类的时候去写自身的拷贝方法,一来类显得有点臃肿,二来不是自动生成的类会增加工作量,只要我这个方法用起来没任何问题,效率又高,为……


我的建议是,将这个做成一个框架。允许用户用Attribute说明如何深拷贝。然后给出不同的策略。这是实用化必须的。 --------------------编程问答-------------------- 改好了,博客中的代码重新编辑过了,之前复制过代码的重新复制下,也可以单独修改以下内容(这也是我代码放博客的一个原因,随时可以修改,传附件或放论坛,都没法修改)。

if (!field.FieldType.IsValueType)
改为了
if (!field.FieldType.IsValueType && field.FieldType != typeof(String))

因为String是不可修改的,对其不需要深拷贝,直接传其引用地址即可。 --------------------编程问答-------------------- 占座学习,,,以前都没有关注 --------------------编程问答--------------------
引用 12 楼 caozhy 的回复:
我的建议是,将这个做成一个框架。允许用户用Attribute说明如何深拷贝。然后给出不同的策略。这是实用化必须的。

没问题,在这个基础上稍作修改就可以实现你要的功能,具体判断在foreach循环的时候,先获取Attribute。

另外我为了提高效率,只针对了field进行拷贝,property无视,因此Attribute如果是定义在了property上面的,需要使用另一个方案——property的深度拷贝,其原理基本相同。作为抛砖引玉,如果可以看懂我写的那方法,增加自己需要的Attribute是完全没问题的,至少我目前不需要任何的限定。 --------------------编程问答-------------------- 先支持一下。 --------------------编程问答--------------------
引用 15 楼 qldsrx 的回复:
另外我为了提高效率,只针对了field进行拷贝,property无视,因此Attribute如果是……


确实没有必要拷贝property,只需要拷贝完整的field就可以达到对象的完整拷贝,正如我们序列化对象时只需要序列化field一样。如果我们把property看成是一种method的特殊封装,更容易理解这一点。

另外,其实如版主所说,通用的深拷贝其实还是有其适用场合,我觉得类似序列化,ORM等场景下使用是最合适的。 --------------------编程问答-------------------- --------------------编程问答-------------------- 不错学习了,,,,,, --------------------编程问答-------------------- 好东西啊,支持一下!!! --------------------编程问答-------------------- 学习;顶一个; --------------------编程问答-------------------- 学习一下,感谢楼主! --------------------编程问答-------------------- 好东西啊,支持一下。 --------------------编程问答-------------------- 看了下,IL不是那么难理解啊。找个时间好好学习下。

最后推荐大家把代码都发布到 NuGet 上  --------------------编程问答-------------------- 学习一下!~ --------------------编程问答-------------------- 好东西啊,支持一下。 --------------------编程问答-------------------- --------------------编程问答-------------------- 好东西,!!!! --------------------编程问答-------------------- 好东西啊,支持一下。  --------------------编程问答-------------------- 好东西啊,支持一下。   --------------------编程问答--------------------    收藏,虽然不搞C# --------------------编程问答-------------------- 好,支持一下 --------------------编程问答-------------------- 谢谢楼主分享 --------------------编程问答-------------------- 很好很好很好 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 楼主无私,顶起你 --------------------编程问答-------------------- 这代码写得挺神。  --------------------编程问答-------------------- 学习了,支持一下 --------------------编程问答-------------------- ok thonak --------------------编程问答-------------------- 好东西,顺便接分 --------------------编程问答-------------------- 好东西大家看看吧 --------------------编程问答-------------------- QQQQQQQQQQQQQQQQQQQ` --------------------编程问答-------------------- 学习沙发, --------------------编程问答-------------------- 饿。这种汇编的变种兄弟真心不好学呀 --------------------编程问答-------------------- 除 --------------------编程问答--------------------

/// <summary>
        /// 深度COPY
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepClone<T>(T obj)
        {
            T objResult;
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(ms, obj);
                ms.Position = 0;
                objResult = (T)bf.Deserialize(ms);
            }

            return objResult;
        }
--------------------编程问答-------------------- --------------------编程问答-------------------- 顶一个 --------------------编程问答-------------------- 赞一下。。。 --------------------编程问答-------------------- 感兴趣的朋友,可以研究下Emit部分,这是C#的精华,也是能够提高效率的必备利器,嫌.NET慢的人不要光抱怨,那是因为你们不懂优化代码,会了Emit就可以最高限度的优化代码 --------------------编程问答-------------------- 这代码写得挺神。  --------------------编程问答-------------------- 发现复制List<int>是没问题的,但复制
    class MyClass1 : List<int>
    {
    }
的实例的话,元素没有被复制 --------------------编程问答-------------------- 好东西啊 --------------------编程问答-------------------- 来学习一下,顺便帮顶! --------------------编程问答-------------------- 除 --------------------编程问答--------------------
引用 5 楼 lizhibin11 的回复:
这代码写得挺神。


PS 技术有待加强啊 同学 --------------------编程问答-------------------- 好东西 正在消化中.... --------------------编程问答-------------------- 好东西 正在消化中....  --------------------编程问答-------------------- 收藏  学习了 --------------------编程问答-------------------- --------------------编程问答-------------------- 占位学习
关注.net的性能优化。 --------------------编程问答-------------------- 不错。。。。。。。。。。。。。 --------------------编程问答-------------------- 收藏  学习了  --------------------编程问答-------------------- --------------------编程问答--------------------
引用 52 楼 phommy 的回复:
发现复制List<int>是没问题的,但复制
    class MyClass1 : List<int>
    {
    }
的实例的话,元素没有被复制

多谢提醒,这个是由于派生类中无法直接反射基类的私有成员,要处理该问题,需要对类的继承链进行遍历查找field,并在每种基类的状态下进行field的复制。这种情况的复制就比较复杂了,等有时间改进下。
--------------------编程问答-------------------- --------------------编程问答-------------------- 这代码写得挺神。 --------------------编程问答-------------------- 学习了~不错 --------------------编程问答--------------------
引用 65 楼 qldsrx 的回复:
引用 52 楼 phommy 的回复:
发现复制List<int>是没问题的,但复制
    class MyClass1 : List<int>
    {
    }
的实例的话,元素没有被复制
多谢提醒,这个是由于派生类中无法直接反射基类的私有成员,要处理该问题,需要对类的继承链进行遍历查找field,并在每种基类的状态下进行field的复制。这种情况的复制就比较复杂了,等有时间……

很重要的问题............. --------------------编程问答-------------------- 学习 学习 NICE --------------------编程问答-------------------- 不错,学习了! --------------------编程问答-------------------- learning~~ --------------------编程问答-------------------- 有点神,顶!! --------------------编程问答-------------------- look规范供货方还 --------------------编程问答--------------------
引用 50 楼 www_baijiale002_com 的回复:
感兴趣的朋友,可以研究下Emit部分,这是C#的精华,也是能够提高效率的必备利器,嫌.NET慢的人不要光抱怨,那是因为你们不懂优化代码,会了Emit就可以最高限度的优化代码
--------------------编程问答-------------------- 好东西,学习了 --------------------编程问答-------------------- --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 这个代码看不懂! --------------------编程问答-------------------- 必然有用途,学以致用! --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 很简单啊 --------------------编程问答-------------------- 啊爱神?
啊飒飒大 --------------------编程问答-------------------- 学习学习,顶一个 --------------------编程问答--------------------
引用 52 楼 phommy 的回复:
发现复制List<int>是没问题的,但复制
    class MyClass1 : List<int>
    {
    }
的实例的话,元素没有被复制

已修复,请重新到博客复制代码。 --------------------编程问答-------------------- 差距好大呀。。 --------------------编程问答-------------------- 好东西啊,支持一下 --------------------编程问答-------------------- 好东西啊,支持一下............................... --------------------编程问答-------------------- 很好!顶一下。。。。 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 非常不错,very good. --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 学习中......... --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 自主创新的么? --------------------编程问答-------------------- 好东西啊,支持一下 --------------------编程问答-------------------- --------------------编程问答--------------------
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,