【c#基础】特殊集合2-可观察的集合 不变集合

一:可观察的集合

如果需要知道集合中的元素何时删除或添加的信息,就可以使用ObservableCollection<T>类。

.Net Core中要使用,需要引用Nuget包System.ObjectModel。这个类的名称空间是System.Collections.ObjectModel.

ObservableCollection<T>类派生自Collection<T>基类。该基类用于创建自定义集合。并在内部使用List<T>类。重写基类中的虚方法SetItem()和RemoveItem(),以触发CollectionChanged事件。这个类的用户就可以使用INotifyCollectionChanged接口注册这个事件。

TODO:INotify 貌似很多地方有很多这个 后面在查相关信息

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5 
 6             var data = new ObservableCollection<string>();
 7             data.CollectionChanged += Data_CollectionChanged;
 8             data.Add("One");
 9             data.Add("Two");
10             data.Insert(1, "Three");
11             data.Remove("One");
12             Console.WriteLine("Hello World!");
13         }
14 
15         public static void Data_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
16         {
17             Console.WriteLine($"action:{e.Action.ToString()}");
18             if (e.OldItems != null)
19             {
20                 Console.WriteLine($"starting index for old items:{e.OldStartingIndex}");
21                 Console.WriteLine("old items:");
22                 foreach (var item in e.OldItems)
23                 {
24                     Console.WriteLine(item);
25                 }
26             }
27 
28             if (e.NewItems != null)
29             {
30                 Console.WriteLine($"starting index for new items:{e.NewStartingIndex}");
31                 Console.WriteLine("new items:");
32                 foreach (var item in e.NewItems)
33                 {
34                     Console.WriteLine(item);
35                 }
36             }
37 
38             Console.WriteLine();
39         }

不变的集合:

如果对象可以改变其状态,就很难在多个同时运行的任务中使用。这些集合必须同步。

如果对象不能改变其状态,就很容易在多个线程中使用。不能改变的对象称为不变的对象。

不能改变的集合称为不变的集合。

为了使用不可变的集合。可以添加Nuget包System.Collections.Immutable。这个库命名空间

System.Collections.Immutable中的集合类。

只读集合利用可变集合的接口。使用这个接口,不能改变集合。如果有人仍然引用可变的集合。

它就仍然可以改变。对于不可变的集合,没有人可以改变这个集合。

在使用不变数组的每个阶段,都没有复制完整的集合。相反,不变类型使用了共享状态,仅在需要时复制集合。

但是,先填充集合,再将它b变成不变的数组会更高效。

 1   public class Account
 2     {
 3         public string  Name { get; set; }
 4         public decimal Balance { get; set; }
 5 
 6         public Account(string name,decimal balance)
 7         {
 8             Name = name;
 9             Balance = balance;
10         }
11     }
 1   var accounts = new List<Account>()
 2             {
 3                 new Account("Scrooge McDuck",667377678765m),
 4                 new Account("Donald Duck",-200m),
 5                 new Account("Ludwig von Drake",2000m),
 6             };
 7             //使用ToImmutableList扩展方法创建一个不变的集合。
 8             ImmutableList<Account> immutableList = accounts.ToImmutableList();
         //也可以像其他集合那样枚举,只是不能改变。
9 foreach (var account in immutableList) 10 { 11 Console.WriteLine($"{account.Name} {account.Balance}"); 12 }

不实用foreach语句迭代不变的列表,也可以使用ImmutableList<T>定义的foreach()方法,这个方法需要一个Action<T>委托作为参数。因此可以分配lambda表达式。

1  accounts.ForEach(a => Console.WriteLine($"{a.Name} {a.Balance}"));

为了处理这些集合,可以使用Contains、FindAll、FindLast、IndexOf()等方法。

如果需要更改不变集合的内容,集合提供了Add、AddRange、Remove、RemoveAt、RemoveRange、Replace以及Sort方法。这些方法非常不同于正常的集合类。因为用于调用方法的不可变集合永远不会改变,但是这些方法放回一个新的不可变集合。

 二:使用构建器和不变的集合

从现有的集合中创建新的不变集合,可以使用前述的Add、Remove和Replace方法完成。

如果需要进行多个修改,如在新集合中添加和删除元素,这就不是非常高效。为了通过进行更多的修改来创建新的不变集合,可以创建一个构建器。

 1 ImmutableList<Account>.Builder builder = immutableList.ToBuilder();
 2             for (int i = 0; i < builder.Count; i++)
 3             {
 4                 Account a = builder[i];
 5                 if (a.Balance <= 0)
 6                 {
 7                     builder.Remove(a);
 8                 }
 9             }
10 
11             var overdrawnAccounts = builder.ToImmutable();

除了使用Remove方法删除元素之外,Builder类型还提供了方案Add、AddRange、Insert、RemoveAt、RemoveAll、Reverse以及Sort,来改变可变的集合,完成可变的操作后,调用ToImmutable,再次得到不变的集合。

三:不变集合类型和接口

 与正常的集合类一样,不变的集合也实现了接口,例如IImmutableQueue<T>、IImmutableList<T>、以及IImmutableStack<T>。这些不变接口的最大区别是所有改变集合的方法都返回一个新的集合。

四:使用Linq和不变的数组

为了使用Linq和不变的数组,类ImmutableArrayExtensions定义了Linq方法的优化版本,

例如:Where、Aggregate(聚合)、All、First、Last、Select和SelectMany。

要使用优化的版本,只需要直接使用ImmutableArray类型,打开System.Linq名称空间。

使用ImmutableArrayExtensions类型定义的Where方法如下所示,扩展了ImmutableArray<T>

类型。

public static IEnumerable<T> Where<T>(this ImmutableArray<T> immutableArray,Func<T,bool> predicate);

 正常的Linq扩展方法扩展了IEnumerable<T>,因为ImmutableArray<T> 是一个更好的匹配,所以使用优化版本调用Linq方法。

原文地址:https://www.cnblogs.com/SignX/p/11318708.html