如何完整传递列表?

时间:2016-05-06 19:59:26

标签: c#

我使用一个列表来包含从XML文件解析的数据,使用字符串作为其成员:

public class ServerList
{
    public string ServerName { set; get; }
    public string ServerReboot { set; get; }
    public string ServerShutdown { set; get; }

    public ServerList()
    {
        ServerName = "";
        ServerReboot = "";
        ServerShutdown = "";
    }
}

从主窗体中我启动一个编辑器表单并将列表传递给它。在此编辑器表单上,用户可以在列表中添加或删除条目条目,以及对列表的某些部分进行更改。如果他们单击“确定”按钮,我希望能够将编辑器表单中的列表拉回到主窗体中,但如果他们单击“取消”,我希望删除这些更改。这是编辑器表单的提取方式:

    private void mnuEdit_Click(object sender, EventArgs e)
    {
        frmEditor theEditor = new frmEditor();
        theEditor.updatedServerList = theServerList;
        DialogResult res = theEditor.ShowDialog();

        if (res == DialogResult.OK)
        {
            theServerList = theEditor.updatedServerList.ToList();
            SetupFilters(GroupOrBatch.Group);
            // other processing to update the main form from the updated list
        }
    }

在编辑表格中,这是如何收到的:

public partial class frmEditor : Form
{
    private List<ServerList> myServerList = new List<ServerList>();

    public List<ServerList> updatedServerList
    {
        get { return myServerList; }
        set { myServerList = value.ToList(); }
    }
....

我发现,虽然列表结构似乎被复制到新变量,但实际数据仍然链接到原始列表。即使用户单击“取消”,并且修改后的列表未复制回原件,原件也已更改。

这给我留下了两个选项之一 - 或者我可以找到一些方法来对列表进行全深度克隆(可以在取消时删除),或者我完全删除取消按钮并且所有编辑都是实时的。

2 个答案:

答案 0 :(得分:1)

class通过引用存储在列表中。 .ToList()仅使用指向那些ServerList的相同引用创建列表的浅表副本。因此,通过对卷影副本进行任何更改,原始列表仍会受到影响。

您需要对列表进行深层复制,并传递它们以进行编辑:

<强> SERVERLIST ::克隆

public class ServerList
{
    // properties...
    // ctor...

    public ServerList Clone()
    {
        return new ServerList
        {
            ServerName = ServerName,
            ServerReboot = ServerReboot,
            ServerShutdown = ServerShutdown,
        });
    }
}

<强> mnuEdit_Click

private void mnuEdit_Click(object sender, EventArgs e)
{
    frmEditor theEditor = new frmEditor();
    theEditor.updatedServerList = theServerList.Select(x => x.Clone()).ToList(); /*changed */
    DialogResult res = theEditor.ShowDialog();

    if (res == DialogResult.OK)
    {
        theServerList = theEditor.updatedServerList; /* changed */
        SetupFilters(GroupOrBatch.Group);
        // other processing to update the main form from the updated list
    }
}

注意:.ToList()上的updatedServerList.get不是必需的。

答案 1 :(得分:0)

作为替代方案,由于您的数据集非常小,请将数据转换为结构:

public struct ServerList
{
    public string ServerName { get; private set; }
    public string ServerReboot { get; private set; }
    public string ServerShutdown { get; private set; }

    public ServerList(string name, string reboot, string shutDown)
    {
        this.ServerName = name;
        this.ServerReboot = reboot;
        this.ServerShutdown = shutDown;
    }
}

struct是值类型(与引用类型相对),值语义将应用于它。请考虑以下事项:

var listA = new ServerList("Foo", "Daily", "Never");
var listB = listA;

listA及其所有值的副本存储在listB中,而不是参考。对于字符串,引用了副本,但字符串无论如何都是不可变的,因此没有问题。

CON:结构应该是不可变的。初始化它们后,您无法更改其数据。在采用此解决方案之前考虑一下。