C# 实现数组深拷贝的一种标准方法

首先让你的数据类实现接口 ICloneable

比如:

     public class Info : INotifyPropertyChanged, ICloneable
     {

        // 实现ICloneable的Clone函数
        public object Clone()
        {
            return this;  //注意这里返回this
        }
        

        public Info(string time, string name, double score, string result)
        {
            this.Time = time;
            this.Name = name;
            this.Score = score;
            this.Result = result;

        }
        
        
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }

        

        private string time;
        public string Time
        {
            get { return time; }
            set
            {
                time = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Time"));
            }
        }

        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Name"));
            }
        }


        private double score;
        public double Score
        {
            get { return score; }
            set
            {
                score = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Score"));
            }
        }



        private string result;
        public string Result
        {
            get { return result; }
            set
            {
                result = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Result"));
            }
        }

    }

那我们的数组就是该数据类的数组,为了让这个深拷贝方法通用,我们使用泛型.

这里我们使用的集合类型是ObservableCollection,你也可以改为List,或者其他类型。

        public static ObservableCollection<T> DeepCopy<T>(IEnumerable<T> list)
            where T : ICloneable
        {
            return new ObservableCollection<T>(list.Select(x => x.Clone()).Cast<T>());          
        }

Select 表示将表中的元素映射到另一张表。Cast表示转换集合中的每个元素的类型。

具体的使用方法如下:

//保留一个备份
infos_copy = DeepCopy<Info>(infos); //其中infos的类型:ObservableCollection<Info>

这样就实现了一个集合的拷贝。

----------------------------------------------------------------------------

还有一个更通用的方法,可以设拷贝任何可序列化的对象

首先我们需要定义个拓展方法,请回顾一下拓展方法的语法。

/// <summary>
/// 对象的深拷贝对象。
/// 注意“T”及其里面的引用类型必须标记为可序列化。
/// </summary>
public static T Copy<T>(this T obj) 
	where T : class
{
	using (var ms = new MemoryStream())
	{
		var bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
		bf.Serialize(ms, obj);
		ms.Seek(0, SeekOrigin.Begin);
		T CloneObject = default(T);

		try
		{
			// 反序列化至另一个对象(即创建了一个原对象的深表副本) 
			CloneObject = (T)bf.Deserialize(ms);
		}
		catch (Exception ex)
		{
			LogHelper.Error("深拷贝对象失败", ex);
		}

		return CloneObject;
	}
}

首先这里用到了this去去修饰一个泛型,而且这个泛型被约束为一个class类型。

也就是说,这个Copy函数几乎是为所以类写的扩展函数. 当然前提是这个类是可序列化的。

如果你需要深拷贝自定义的类,你需要为你的类添加一个[Serializable]标记:

[Serializable]
public class InfoAxisParameter
{
        .....
}

那么使用的时候就十分的方便了:

InfoAxisParameter info = new InfoAxisParameter()
var info_copy = info.Copy()

这里有个小技巧,就是写一个扩展的类TypeExtension,然后将namespace设置为System

这样只要在工程里添加了这个TypeExtension类,那么其他地方无需添加其他的using就能使用这个扩展方法了

namespace System
{
    public static partial class TypeExtension
    {
        /// <summary>
        /// 对象的深拷贝对象。
        /// 注意“T”及其里面的引用类型必须标记为可序列化。
        /// </summary>
        public static T Copy<T>(this T obj) 
            where T : class
        {
            using (var ms = new MemoryStream())
            {
                var bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
                bf.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                T CloneObject = default(T);

                try
                {
                    // 反序列化至另一个对象(即创建了一个原对象的深表副本) 
                    CloneObject = (T)bf.Deserialize(ms);
                }
                catch (Exception ex)
                {
                    LogHelper.Error("深拷贝对象失败", ex);
                }

                return CloneObject;
            }
        }
}

posted @ 2021-08-12 16:19  宋桓公  阅读(160)  评论(0编辑  收藏  举报