3

我有一个应用程序,它有一个数据树作为数据后端。为了实现 MVVM 模式,我有一个封装数据树的类的逻辑层。因此逻辑也被安排在树中。如果输入处于有效状态,则应将数据复制到第二个线程,该线程用作最后一个有效状态的双缓冲区。因此,一种方法是克隆。

另一种方法是将完整的数据后端实现为不可变的。如果输入新内容,这将意味着重建整个数据树。我的问题是,有没有实用的方法来做到这一点?我被困在必须将数据树有效地重新分配给逻辑层的地步。

**更新 - 一些代码

我们正在做的是抽象出我们用来运行实验的硬件设备。因此,我们定义了诸如“机箱、序列、卡片、通道、步骤”之类的类。那些构建一个像这样的树结构:

                            Chassis
                          /      \
                   Sequence1      Sequence2
                   /    |    \
              Card1   Card2  Card3
             /     \
     Channel1      Channel2
    /        \
Step1        Step2

在代码中它看起来像这样:

public class Chassis{

readonly var List<Sequence> Sequences = new List<Sequence>();

}

public class Sequence{

readonly var List<Card> Cards = new List<Card>();

}

等等。当然,每个类都有更多属性,但这些属性很容易处理。我现在的问题是 List 是一个可变对象。我可以调用 List.Add() 并且它改变了。好的,有一个 ReadOnlyList 但我不确定它是否以正确的方式实现了不变性。就像按值复制而不是引用,而不仅仅是通过阻止 set 方法来阻止写入它。下一个问题是序列和步骤的数量可能会有所不同。出于这个原因,我需要列表元素的原子交换。目前我没有更多的代码,因为我仍在考虑这种方式是否对我有帮助,以及是否有可能在合理的时间内实现它。

4

2 回答 2

4

请注意,有一些新的 .NET 不可变集合可以帮助您实现目标。

对 Dave Turvey 的声明要非常谨慎(如果可以的话,我会投反对票/评论):

如果您希望实现一个不可变列表,您可以尝试将列表存储为私有成员但公开IEnumerable<>

这是不正确的。私有成员仍然可以通过其容器类进行更改。公共成员可以强制转换为List<T>, IList<T>, 或ICollection<T>不抛出异常。因此,任何依赖于公众不变性的东西都IEnumerable<T>可能破裂。

于 2013-01-15T17:23:28.480 回答
0

我不确定我是否 100% 理解您的要求。听起来您有一棵处于特定状态的对象树,并且您希望在不修改原始对象状态的情况下对其副本执行一些处理。您应该考虑通过“深度复制”进行克隆。这个问题应该让你开始。

如果您希望实现一个不可变列表,您可以尝试将列表存储为私有成员但公开IEnumerable<>

public class Chassis
{

   List<Sequence> _sequences = new List<Sequence>();
   public IEnumerable<Sequence> Sequences { get { return _sequences; } }

}

2013 年 4 月 18 日更新以回应布兰登邦兹的评论

Brandon Bonds 答案中链接的库当然很有趣,并且比IEnumerable<>. 在许多情况下,它可能是一个更好的解决方案。但是,如果您使用此库,则应该注意一些警告。

  1. 截至 2013 年 4 月 18 日,这是一个 beta 库。它显然仍在开发中,可能还没有准备好用于生产。例如,链接文章中的列表创建代码示例在当前的 nuget 包中不起作用。

  2. 这是一个 .net 4.5 库。因此它不适用于针对旧框架的程序。

  3. 它不保证仅集合本身的集合中包含的对象的不变性。可以修改不可变列表中的对象 您仍然需要考虑使用深层副本来复制集合。

这在文章末尾的常见问题解答中得到解决

问:我可以只在这些不可变集合中存储不可变数据吗?

答:您可以在这些集合中存储所有类型的数据。唯一不变的方面是集合本身,而不是它们包含的项目。

此外,以下代码示例说明了这一点(使用版本 1.0.8-beta)

class Data
{
    public int Value { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var test = ImmutableList.Create<Data>();           
        test = test.Add(new Data  { Value = 1 });
        Console.WriteLine(test[0].Value);
        test[0].Value = 2;
        Console.WriteLine(test[0].Value);
        Console.ReadKey();
    }
}

此代码将允许修改 Data 对象和输出

1
2

这里有几篇文章可以进一步阅读这个主题

于 2012-11-07T12:38:35.203 回答