public class oddsRecoder : ICloneable, IDisposable
{
    private bool bool_0;
    private string _guid = string.Empty;
    public IDictionary<string, IDictionary<string, IDictionary<string, string>>> dictionary = new Dictionary<string, IDictionary<string, IDictionary<string, string>>>();
    private IDictionary<string, dic_PlayData> DataCollection = new Dictionary<string, dic_PlayData>();    public object Clone()
    {
        try
        {
            MemoryStream serializationStream = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(serializationStream, this);
            serializationStream.Position = 0L;
            Thread.GetDomain().AssemblyResolve += new ResolveEventHandler(this.m0000ca);
            object obj2 = formatter.Deserialize(serializationStream);
            Thread.GetDomain().AssemblyResolve -= new ResolveEventHandler(this.m0000ca);
            return obj2;
        }
        catch (Exception ex)
        {
            Console.Write(ex.Message); Log.a(ex, 1000);
        }
        return null;
    }    public void Dispose()
    {
        this.m000075(true);
        GC.SuppressFinalize(this);
    }
 
一个存放数据的类,结果发现在复制的时候相当费时,有没有更高效的方法,这里的dic_PlayData类,也有很多idictionary、string、datetime等成员,一个一个复制可能比较麻烦,大家是怎么做的呢?

解决方案 »

  1.   

    有个老外写的快速深度克隆,里面有讲到每种克隆的效率。还有源码你可以看下
    http://blog.nuclex-games.com/mono-dotnet/fast-deep-cloning/
      

  2.   

    TO:qldsrx
    是啊,可是这样真的效率很差啊,有没有更好的办法呢
      

  3.   

    其实是看你的执行次数,如果不是重复多次克隆,或者要大量克隆,就不需要考虑那个效率。否则你可以考虑Emit进行动态创建方法。
      

  4.   

       public class Team 
    {
      public virtual Team Clone2()
            {
                Team c = new Team();
                c.Time = this.Time;  
                c.RaceName =this.RaceName;
                 c.Name = this.Name;
                c.RightName = this.RightName;
                c.Score = this.Score;
                c.VSName= this.VSName;
                return c;
                
            }
    }   public class ChildrenTeam 
    {
      public override ChildrenTeam  Clone2()
            {
                ChildrenTeam c = new ChildrenTeam();
                c.Time = this.Time;  
                c.RaceName =this.RaceName;
                 c.Name = this.Name;
                c.RightName = this.RightName;
                c.Score = this.Score;
                c.VSName= this.VSName;
    //基类特有的变量
    c.ID=this.ID;
                return c;
                           
            }
    }自身拷贝算了,继承类的COLNE是不是写的太麻烦了点,如果有好几个继承类的话,每个都得改,这样“  ChildrenTeam c = base.Clone2() as ChildrenTeam ;  c._ID=this.ID”貌似可以解决,但面临装箱拆箱的效率问题,大家有没有更好的写法?
      

  5.   

    用Emit啊,我5楼都提到过了,那个不但速度和硬编码一样(或许比硬编码更快),还有通用性,写好一个,任何类型都可用。你先自己查查资料,我这几天比较忙,最多帮你写个普通类(带继承)的Clone,累死你上面举例的类,对于特殊类型如IList、IDictionary的Clone,就不能帮忙了。
      

  6.   

    你说的EMIT,是不是反射?反射效率也很低啊
      

  7.   

    我们手写的代码,也会是IL啊,知道源代码了,何需要EMIT啊,还不懂,楼上能多讲一下吗?如何CLONE一个类,通过EMIT
      

  8.   

    你对类中的一个个属性赋值,手写代码要写多少?每个类都要写一遍,内部每个属性的赋值都要写上去,要多少工作量你想过吗?当然这样也是执行效率最高的,但是通过EMIT就可以实现通用方法,让机器代替人工去硬编码。
      

  9.   

    有一个开源FastSerializer c#服务器程序大都是用他。不过也是来自国外。
    这个国际用的比较多。据国外的一个测试效率是最高的。
    但不知道是不是和二楼给出是不是同一个。
      

  10.   

    2楼给的还不算最高,如果就是那个,肯定不是最高。它那个是用LINQ的表达式树进行序列化和反序列化达到复制的目的,所以不可能快到哪里去,而实际给出的曲线图也并没有显示多大的优势。
    用Emit,效率可以比序列化提高一百倍左右,信不信由你。
      

  11.   

    给你写了一段简单的Emit代码,只支持简单类型的类(属性都为基础数据类型),真的是很忙,没时间分析负责类型,仅为了证明这个方法是最快的,手写都没这速度。
    核心代码:
            static List<FieldInfo> GetSettableFields(Type t)
            {
                return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList();
            }
            //暂时只能支持简单类的克隆,也就是类的内部只有基础类型。
            static Func<object, object> CreateCloneMethod(Type type)
            {
                var fields = GetSettableFields(type);
                var dm = new DynamicMethod(string.Format("Clone{0}", Guid.NewGuid()), typeof(object), new[] { typeof(object) }, true);
                var il = dm.GetILGenerator();
                il.DeclareLocal(type);
                il.DeclareLocal(type);
                il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc_1);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Castclass, type);
                il.Emit(OpCodes.Stloc_0);
                foreach (var field in fields)
                {
                    il.Emit(OpCodes.Ldloc_1);
                    il.Emit(OpCodes.Ldloc_0);
                    il.Emit(OpCodes.Ldfld, field);
                    il.Emit(OpCodes.Stfld, field);
                }
                il.Emit(OpCodes.Ret);            return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));
            }
    验证(如果不是深度复制,而是引用赋值,这里面if判断将会相等而不输出u2的内容):            Func<object, object> clone = CreateCloneMethod(typeof(DT_USER));
                DT_USER u1 = new DT_USER() { USER_NO = 1, USER_LNAME = "001" };
                DT_USER u2 = clone(u1) as DT_USER;
                if (u1 != u2)
                {
                    Console.WriteLine(u2.USER_LNAME);
                }
      

  12.   

    效率比较:Func<object, object> clone = CreateCloneMethod(typeof(DT_USER));
    DT_USER u1 = new DT_USER() { USER_NO = 1, USER_LNAME = "001" };
    DT_USER u2 = null;Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < 100000; i++)
    {
        u2 = u1.Clone();
    }
    sw.Stop();
    Console.WriteLine("手写代码克隆执行10万次所用时间:" + sw.ElapsedMilliseconds + "毫秒");sw.Restart();
    for (int i = 0; i < 100000; i++)
    {
        u2 = clone(u1) as DT_USER;
    }
    sw.Stop();
    Console.WriteLine("Emit执行10万次所用时间:" + sw.ElapsedMilliseconds + "毫秒");sw.Restart();
    for (int i = 0; i < 100000; i++)
    {
        MemoryStream serializationStream = new MemoryStream();
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(serializationStream, u1);
        serializationStream.Position = 0;
        u2 = formatter.Deserialize(serializationStream) as DT_USER;
        serializationStream.Close();
    }
    sw.Stop();
    Console.WriteLine("序列化方式执行10万次所用时间:" + sw.ElapsedMilliseconds + "毫秒");输出结果为:
    手写代码克隆执行10万次所用时间:28毫秒
    Emit执行10万次所用时间:18毫秒
    序列化方式执行10万次所用时间:6185毫秒
    这里要注意:那个CreateCloneMethod创建的委托必须缓存后才能重复使用,缓存的方式很简单,定义一个全局静态字典Dictionary<Type,Func<object, object>>,由于每个具体的Type只能对应一个Clone委托,那么你的程序运行中只要创建一次Clone委托,就可以重复使用了,执行效率最高。
      

  13.   

    要是跟我一样对Emit不熟的话还是硬编码执行速度最快了。
      

  14.   

    TO:qldsrx
       对于你的这个测试,我不是很理解,因为硬编码在执行一次就转化为MSIL,跟EMIT一样了,双方应该是一样的吧,我查了一下,貌似整体EMIT的性能接近硬编码,但要差,可能只有在赋值方面,才可以超过,但也是差不多了,他并不能大幅提高性能。
        我的这个类的CLOnE,包括泛型字典,有EMIT有解吗?本想结贴,还没有跟你聊够呢,哈哈~~
      

  15.   

    编译器优化毕竟有限,比如某个值,我可以不用中间变量存储,直接推送到堆栈上面处理完全过程,但是写代码的时候不能直接操作堆栈,因此需要有个中间变量存储操作的中间过程,这就导致了编译后的IL代码中多了个中间变量交换过程。而你这个Clone本身就是内部值的交换,少点交换的中间变量,自然能够提高速度。
    另外你似乎不懂什么叫“运行时”,那个EMIT创建的方法是“运行时”方法,不同于直接C#编写的方法,“运行时”方法是不能被编译器语法检测的,出错也只能在运行时被发现,编译的时候根本就没那个方法存在,自然无法检测是否有错误。“运行时”创建方法最大的好处是可以结合当时的实际情况来创建,条件变了,创建的方法就不同,这里所谓的条件改变,就是要Clone的类型对象改变。这样就达到了一次编程,多处使用了。否则你要为每个类创建的时候都写一遍Clone方法,内置类型还无法直接编写。
      

  16.   

    我都说了只能支持简单类型,所以不完善。但是不考虑是没道理的,像你这样的能力的人,只要简单几个递归嵌套下,就能实现复杂类型的Clone,任何复杂的类型,都是由简单类型组成的。
      

  17.   

       很欣赏qldsrx的作法,这个EMIT没太多涉及,可能搞不了,但毕竟为我们开了扇窗,很高兴知道一些能提高性能的方法。在此结贴,感觉大家的支持