C# 复制对象或具有复制属性的新对象?

C# 复制对象或具有复制属性的新对象?,c#,visual-studio-2010,oop,C#,Visual Studio 2010,Oop,我正在制作一个文件备份程序,使用配置文件保存设置等。目前的结构如下: MainForm有一个ProfileHandler,它有一组概要文件对象 在程序中进行任何更改(将文件添加到列表、更改目标路径等)时,设置将保存在临时配置文件中。到目前为止,一切都很好 但是,当我想保存个人资料时,我真的无法决定该走哪条路。现在,我将临时概要文件对象传递给ProfileHandler中的AddProfile方法。然后,该方法使用临时配置文件对象中的属性作为参数创建一个新的配置文件对象(除了列表,该列表仅使用Ad

我正在制作一个文件备份程序,使用配置文件保存设置等。目前的结构如下:

MainForm
有一个
ProfileHandler
,它有一组概要文件对象

在程序中进行任何更改(将文件添加到列表、更改目标路径等)时,设置将保存在临时配置文件中。到目前为止,一切都很好

但是,当我想保存个人资料时,我真的无法决定该走哪条路。现在,我将临时概要文件对象传递给
ProfileHandler
中的
AddProfile
方法。然后,该方法使用临时配置文件对象中的属性作为参数创建一个新的配置文件对象(除了
列表
,该列表仅使用Addrange复制内容)

它有效,但它好吗

public bool AddProfile(Profile tempProfile)
{
    if (tempProfile != null)
    {
        Profile profile = new Profile(tempProfile.Name, tempProfile.TargetPath);
        profile.Filelist.Clear();
        profile.Filelist.AddRange(tempProfile.Filelist);
        _profiles.Add(profile);
    }
    return (tempProfile != null);
}
有更巧妙的方法吗? 不知何故,我觉得必须有一种简单的方法来创建
Profile
对象的新实例,它是
temprofile
的简单副本。在我的例子中,
Profile
类只有三个字段,这使它变得简单,但是如果它有很多字段呢


我希望我不太清楚。我对这一点有点陌生。

你可以对你的
temprofile
进行深度复制并保存。 下面是示例代码 来源

publicstatict-DeepClone(T-obj)
{
使用(var ms=new MemoryStream())
{
var formatter=新的二进制格式化程序();
序列化(ms,obj);
ms.Position=0;
返回(T)格式化程序。反序列化(ms);
}
}

只需创建一个构造函数,该构造函数接受一个配置文件,并按如下方式进行复制:

public Profile(Profile profileToCreateFrom)
    : this(profileToCreateFrom.Name, profileToCreateFrom.TargetPath)
{
    FileList = profileToCreateFrom.FileList.Select(file => file).ToList();
}
然后添加具有以下内容的新文件:

_profiles.Add(new Profile(tempProfile));

您可以签出受保护的方法。这种方法早在早期就存在了

void Main()
{
    Profile p = new Profile("bob", @"c:\foo");
    p.FileList.Add("bar.txt");

    Profile copy = p.DeepCopy();
    copy.FileList.Clear();
    copy.FileList.Add("baz.log");

    p.Dump("p");
    copy.Dump("copy");
}

public class Profile
{
    public Profile(string name, string targetPath)
    {
        this.Name = name;
        this.TargetPath = targetPath;
        this.FileList = new List<string>();
    }

    public Profile DeepCopy()
    {
        Profile copy = (Profile)this.MemberwiseClone(); // this takes care of Name & TargetPath
        copy.FileList = new List<string>(this.FileList);
        return copy;
    }

    public string Name { get; private set; }
    public string TargetPath { get; private set; }
    public List<string> FileList { get; private set; }
}
void Main()
{
Profile p=新的Profile(“bob”,“c:\foo”);
p、 添加(“bar.txt”);
配置文件副本=p.DeepCopy();
copy.FileList.Clear();
copy.FileList.Add(“baz.log”);
p、 倾销(“p”);
复制。转储(“复制”);
}
公共班级简介
{
公共配置文件(字符串名称、字符串targetPath)
{
this.Name=Name;
this.TargetPath=TargetPath;
this.FileList=新列表();
}
公共配置文件DeepCopy()
{
Profile copy=(Profile)this.MemberwiseClone();//这负责名称和目标路径
copy.FileList=新列表(此.FileList);
返回副本;
}
公共字符串名称{get;private set;}
公共字符串TargetPath{get;private set;}
公共列表文件列表{get;private set;}
}
您可以将
MemberwiseClone
视为进行浅位复制。这通常适用于int、double、float等值类型,甚至适用于string等不可变引用类型。但是,您需要在profile类中创建可变引用类型(如
List
)的副本,以便副本的突变不会同时更改原始引用类型。就维护而言,这是一条很好的路线——如果您添加了一个新的可变属性,那么您必须记住在克隆发生后在deepcopy方法中进行复制

根据您的设计,您可能不希望复制其他内容,如事件注册。你可以把这些看作是暂时的。如果你的应用程序是多线程的,你也需要小心,在复制过程中,你将不得不像在其他地方一样努力保持对象的完整性(例如锁定)


我没有业绩数字。无论如何,不管你采纳了什么建议,你最适合自己做一些性能测试,看看它是否足够快。

当你的方法被推广时,BinaryFormatter会表现得很糟糕,因为它会进行大量的反射,并通过向它输出的字节数组中添加大量类型数据而浪费大量内存。对于这种一次性场景,只需一个特定于对象的深度复制就可以了。当然,在过去,我不得不用手动序列化程序替换很多BinaryFormatter,呵呵,如果你想要一个性能几乎和手动序列化程序一样好的通用序列化程序,那么在将来看看这个:
void Main()
{
    Profile p = new Profile("bob", @"c:\foo");
    p.FileList.Add("bar.txt");

    Profile copy = p.DeepCopy();
    copy.FileList.Clear();
    copy.FileList.Add("baz.log");

    p.Dump("p");
    copy.Dump("copy");
}

public class Profile
{
    public Profile(string name, string targetPath)
    {
        this.Name = name;
        this.TargetPath = targetPath;
        this.FileList = new List<string>();
    }

    public Profile DeepCopy()
    {
        Profile copy = (Profile)this.MemberwiseClone(); // this takes care of Name & TargetPath
        copy.FileList = new List<string>(this.FileList);
        return copy;
    }

    public string Name { get; private set; }
    public string TargetPath { get; private set; }
    public List<string> FileList { get; private set; }
}