对象的深层拷贝

遇到这么个问题,没有参考任何资料,自己想了个方法

对于自定义的一些简单类型还好,遇到.Net里一些复杂的类就无能为力了,不知道还有什么更好的方法。

 

 

class CsToD
{
    //基本思想是:一个对象所占据的内存空间,取决于它的实例字段(包括继承树上的私有实例字段)
    public T DeepCloneObject<T>(T obj) where T : class
    {
        //System.String类型似乎比较特殊,复制它的所有字段,并不能复制它本身
        //不过由于System.String的不可变性,即使指向同一对象,也无所谓
        //而且.NET里本来就用字符串池来维持
        if (obj == null || obj.GetType() == typeof(string))
            return obj;
        object newObj = null;
        try
        {
            //尝试调用默认构造函数
            newObj = Activator.CreateInstance(obj.GetType());
        }
        catch
        {
            //失败的话,只好枚举构造函数了
            foreach (ConstructorInfo ci in obj.GetType().GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
            {
                try
                {
                    ParameterInfo[] pis = ci.GetParameters();
                    object[] objs = new object[pis.Length];
                    for (int i = 0; i < pis.Length; i++)
                    {
                        if (pis[i].ParameterType.IsValueType)
                            objs[i] = Activator.CreateInstance(pis[i].ParameterType);
                        else
                            //参数类型可能是抽象类或接口,难以实例化
                            //我能想到的就是枚举应用程序域里的程序集,找到实现了该抽象类或接口的类
                            //但显然过于复杂了
                            objs[i] = null;
                    }
                    newObj = ci.Invoke(objs);
                    //无论调用哪个构造函数,只要成功就行了
                    break;
                }
                catch
                {
                }
            }
        }
        foreach (FieldInfo fi in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
        {
            if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
                fi.SetValue(newObj, fi.GetValue(obj));
            else
                fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
        }
        //基类的私有实例字段在子类里检索不到,但它仍占据子类对象的内存空间
        Deep(newObj, obj);
        return (T)newObj;
    }

    //克隆继承树上的私有实例字段
    public void Deep(object newObj, object obj)
    {
        for (Type father = newObj.GetType().BaseType; father != typeof(object); father = father.BaseType)
        {
            foreach (FieldInfo fi in father.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
            {
                //只需要处理私有字段,因为非私有成员已经在子类处理过了
                if (fi.IsPrivate)
                {
                    if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
                    {
                        fi.SetValue(newObj, fi.GetValue(obj));
                    }
                    else
                    {
                        fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
                    }
                }
            }
        }
    }
}

 

 

写个代码来测试一下:

 

class Program
{
    static void Main()
    {
        Data3 data3 = new Data3();
        Data data = new Data(data3);
        data.PriValue = "Pri";
        data.Integer = 3;


        //修改cloneData对象,并未影响到data对象,说明克隆成功
        CsToD ctd = new CsToD();
        Data cloneData = ctd.DeepCloneObject(data);
        cloneData.Integer = 1000;
        cloneData.PriValue = "clone";
        cloneData.Value.D3String = "clonestr";
        Console.WriteLine(data.Integer + "<->" + cloneData.Integer);
        Console.WriteLine(data.PriValue + "<->" + cloneData.PriValue);
        Console.WriteLine(data.Value.D3String + "<->" + cloneData.Value.D3String);


        //而如果修改refData对象,data对象也被改变,说明是同一对象
        Data refData = data;
        refData.Integer = 555;
        refData.PriValue = "ref";
        refData.Value.D3String = "refstr";
        Console.WriteLine(data.Integer + "<->" + refData.Integer);
        Console.WriteLine(data.PriValue + "<->" + refData.PriValue);
        Console.WriteLine(data.Value.D3String + "<->" + refData.Value.D3String);
    }
}
class Data:Data2
{
    public Data(Data3 value)
    {
        this.Value = value;
    }
    public Data() { }
    public Data3 Value;

}
class Data2
{
    public Data2(int value)
    {
        this.Integer = value;
    }
    public string PriValue
    {
        get
        {
            return priValue;
        }
        set
        {
            priValue = value;
        }
    }
    public Data2() { }
    public int Integer;
    private string priValue;
}
class Data3
{
    public Data3()
    {
        D3String = "D3";
        d3Integer = 3;
    }
    public string D3String;
    private int d3Integer;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值