c# 反射getvalue_C#的深拷贝浅拷贝

腾讯前端实习被问了这个问题,我就答了序列化的方式,然后很明显面试官不大满意,当然挂了的原因比较多,我慢慢总结积累一下:

首先要明确拷贝产生的结果都是reference type的,本质上还是指向一个对象(毕竟primitive type不需要)

所以深拷贝和浅拷贝的区别,就是拷贝这个reference指向的对象是不是之前的。

有以下两种方式,更推荐第一种:

1 泛型+反射: https://www.cnblogs.com/TheBob/p/9414014.html

        /* 利用反射实现深拷贝*/
        public static object DeepCopy(object _object)
        {
            Type T = _object.GetType();
            object o = Activator.CreateInstance(T);
            PropertyInfo[] PI = T.GetProperties();
            for (int i = 0; i < PI.Length; i++)
            {
                PropertyInfo P = PI[i];
                P.SetValue(o, P.GetValue(_object));
            }
            return o;
        }

这种我觉得比较好,要理解这个方式首先复习一下反射的定义:

反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外 我还可以直接创建对象,即使这个对象的类型在编译时还不知道。可以实现从对象的外部来了解对象(或程序集)内部结构的功能,哪怕你不知道这个对象(或程序集)是个什么东西,另外.NET中的反射还可以运态创建出对象并执行它其中的方法。
为什么要用反射呢? 举个最简单的例子,当你在VS的设计器里拖入一个控件后,设计器会通过反射获取这个控件的属性,并提供给你进行设置, 设计器在做的时候,根本不可能预知将来有什么控件会被你拖入进去,所以要用反射

所以反射看起来是主要被用于处理一些不可预知的情况,你不知道你要处理啥,比如说我当时学windows用到了反射来处理COM组件。

Type type = Type.GetType("类的完全限定名"); 
dynamic obj = type.Assembly.CreateInstance(type);
// 获取COM的类
public static System.Type t = Type.GetTypeFromProgID("CreateCOM.Class1");
public static dynamic o = Activator.CreateInstance(t);

这样的好处在于,它消除了模块之间的耦合,便于动态接口调用,在一些灵活的系统里面比较常用。

说回我们的主题,反射和泛型来实现深拷贝怎么做?

  • 首先我们应该获取传入参数的那个对象的类型,也就是反射的GetType()
  • 接下来Activator.CreateInstance(T); 用类型创建新拷贝的对象
  • PropertyInfo[] PI = T.GetProperties(); 这里使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
  • 接下来用Property的SetValue和GetValue来给新对象属性逐个赋值
  • 大功告成,返回新对象就行

所以思路很清晰,调用的时候 Test b = (Test)DeepCopy(a); 泛型把object转回来就行

总的来说我觉得这是一种比较简单直接也好理解的方法

2 二进制流的方式(序列化)

/// 深拷贝 【不建议使用二进制流方法,此方法即使在类前面加了可序列化标志,调用该方法时也会报未序列化错误】,推荐使用反射方式
        public object DeepCopy()
        {
            using (MemoryStream stream = new MemoryStream())
            {
                BinaryFormatter bFormatter = new BinaryFormatter();
                bFormatter.Serialize(stream, this);
                stream.Seek(0, SeekOrigin.Begin);
                return (InvoiceDetailResponse)bFormatter.Deserialize(stream);
            }
        }

Emmmm我虽然当时回答这种,但是我其实并不懂.......可能确实这种方式也不大合适

另外我看有博客说用struct 代替class,或者一个一个赋值之类的,这些方式都有一些局限性,个人感觉第一种采取反射加泛型的方式是最好的。

补充:

.net提供了一个ICloneable接口,该接口下有一个Clone()方法,你可以实现它用来实现你自己的克隆方式,比如深克隆或是浅克隆,MemberwiseClone()是object类中的一个方法,用来实现类的浅克隆

比如浅拷贝的实现可以直接调用:当然这和直接=有啥区别我也不懂:( 欢迎大佬指点

public object ShallowCopy()
{
    return this.MemberwiseClone();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值