C#深浅拷贝

前言  等号=赋值是不是拷贝?

  等号赋值相当于复制该变量存在栈上的地址,并不产生分配内存的新对象。两个变量指向同一地址,本质上是修改统一块内存,一个改变所有副本都会变。

    public class Order
    {
        public int OrderNo { get; set; }
        public OrderItem item { set; get; }

    }

    public class OrderItem
    {
        public string SKU { set; get; }
        public int Price { get; set; }
    }


            //构建原始对象o_a
            Order o_a = new Order();
            o_a.OrderNo = 20211126;
         
            OrderItem item = new OrderItem();
            item.Price = 1;
            item.SKU = "XXX";
            o_a.item = item;


            var o_b = o_a;//等号复制o_a存在栈上的地址
            o_b.OrderNo = 20211127;//复制后修改目标对象的值类型
            o_b.item.SKU = "OOO";//复制后修改目标对象的引用类型

            Console.WriteLine(object.ReferenceEquals(o_b,o_a));//输出true
            Console.WriteLine(o_a.OrderNo+"--"+o_a.item.SKU);//输出原始 20211127--OOO  全发生改变。

 

 

一.浅拷贝(拷贝不全)

    浅拷贝对于值类型,浅拷贝会分配新的内存空间将值类型直接拷贝到新对象中。

    对于引用类型,浅拷贝则只会复制引用地址,指向的依然是被原始对象的同一空间。所以目标对象中的引用型字段更改,原始对象相应也会更改。

    public class Order
    {
        public int OrderNo { get; set; }
        public OrderItem item { set; get; }

        //浅复制的方法
        public Order QianCopy()
        {
            return (Order)MemberwiseClone();
        }

    }

    public class OrderItem
    {
        public string SKU { set; get; }
        public int Price { get; set; }
    }


            //构建原始对象o_a
            Order o_a = new Order();
            o_a.OrderNo = 20211126;

            OrderItem item = new OrderItem();
            item.Price = 1;
            item.SKU = "XXX";
            o_a.item = item;


            var o_b = o_a.QianCopy();//浅复制复制出一个o_b

            o_b.OrderNo = 20211127;
            o_b.item.SKU = "OOO";

            Console.WriteLine(o_a.OrderNo + "--" + o_a.item.SKU); //输出原始 20211126--OOO  

 二.深拷贝(完全拷贝)

    完全复制一个新的对象,只是引用地址不同。两个对象互相独立互不影响。深拷贝的方法有多种。

1.NewtonSoft序列化、反序列化(性能损耗大,效率低)

 

    public class Order
    {
        public int OrderNo { get; set; }
        public OrderItem item { set; get; }
    }

    public class OrderItem
    {
        public string SKU { set; get; }
        public int Price { get; set; }
    }

            //构建原始对象o_a
            Order o_a = new Order();
            o_a.OrderNo = 20211126;

            OrderItem item = new OrderItem();
            item.Price = 1;
            item.SKU = "XXX";
            o_a.item = item;

            Order o_b =   Newtonsoft.Json.JsonConvert.DeserializeObject<Order>(Newtonsoft.Json.JsonConvert.SerializeObject(o_a));
            o_b.OrderNo = 20211127;
            o_b.item.SKU = "OOO";
            Console.WriteLine(object.ReferenceEquals(o_a, o_b));//输出false
            Console.WriteLine(o_a.OrderNo + "--" + o_a.item.SKU); //输出原始 20211126--XXX  

 2.使用反射,新建一个反射助手类。

    public class ReflectionHelper
    {
        public static TOut TransRelection<TIn,TOut>(TIn tIn)
        {
            TOut tout = Activator.CreateInstance<TOut>();

            var tInType = tIn.GetType();

            foreach (var item in tout.GetType().GetProperties())
            {
                var itemIn = tInType.GetProperty(item.Name);

                if (itemIn!=null)
                {
                    item.SetValue(tout, itemIn.GetValue(tIn));
                }
            }
            return tout;
        }
    }

调用,得到结果跟上个例子一致

  Order o_b = ReflectionHelper.TransRelection<Order, Order>(o_a);

 

posted @ 2021-11-28 18:57  勇敢肥牛  阅读(74)  评论(0)    收藏  举报