具有MVVM实现的WPF应用程序的不可变数据模型

时间:2012-11-07 03:14:50

标签: wpf mvvm immutability

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

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

**更新 - 部分代码

我们正在做的是抽象我们用来运行实验的硬件设备。因此我们定义了类似“chassis,sequence,card,channel,step”的类。那些构建这样的树结构:

                            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方法来阻止写入它。 下一个问题是序列和步骤的数量可以变化。出于这个原因,我需要列表元素的原子交换。 目前我还没有更多的代码,因为我仍在考虑这种方式是否有助于我,以及是否有可能在合理的时间内实现它。

2 个答案:

答案 0 :(得分:4)

请注意,有新的immutable collections for .NET可以帮助您实现目标。

对Dave Turvey的陈述非常谨慎(如果可以的话,我会downvote / comment):

  

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

这是不正确的。私有成员仍然可以通过其容器类进行更改。公共成员可以投放到List<T>IList<T>ICollection<T>而不会抛出异常。因此,任何取决于公众IEnumerable<T>不变性的事情都可能会破裂。

答案 1 :(得分:0)

我不确定我是否100%理解你的要求。听起来你有一个特定状态的对象树,你想在不修改原始对象状态的情况下对其副本执行某些处理。您应该通过&#34; Deep Copy&#34;来研究克隆。 This question应该让你开始。

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

public class Chassis
{

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

}

18/04/13更新以回应Brandon Bonds的评论

在Brandon Bonds答案中链接的图书馆肯定很有趣,并提供优于IEnumerable<>的优势。在许多情况下,它可能是更好的解决方案。但是,如果您使用此库,则应注意一些注意事项。

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

  2. 这是一个.net 4.5库。所以它不适合针对旧框架的程序。

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

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

      问:我是否只能将不可变数据存储在这些不可变集合中?

         

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

    此外,以下代码示例说明了这一点(使用版本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
    

    以下是一些有关此主题的进一步阅读的文章