支持不可变集合的集合初始化语法-方法的init修饰符



我需要实现一个支持集合初始化语法的不可变集合。问题是为了支持集合初始化语法,集合必须提供适当的public Add((方法。但是,如果集合提供了公共Add((方法,它就不再是不可变的。

我想要实现的目标示例:

var element = new MyElement();
var collection1 = new MyImmutableCollection { element };
var collection2 = new MyImmutableCollection { "ABC" };

为了实现这一点,我需要MyImmutableCollection来实现IEnumerable,并为Add((方法提供适当的签名(关于集合初始化的更多信息,请参阅此处(:

class MyElement
{
public MyElement()
{
}
public MyElement(string label)
{
Label = label;
}
public string Label { get; set; }
}
class MyImmutableCollection : IEnumerable<MyElement>
{
readonly List<MyElement> list = new List<MyElement>();
#region Collection initialization support which breaks immutability
public void Add(MyElement element)
{
list.Add(element);
}
public void Add(string label)
{
Add(new MyElement(label));
}
#endregion
public MyElement this[int index]
{
get { return list[index]; }
set { list.Insert(index, value); }
}
#region IEnumerable support
public IEnumerator<MyElement> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}

然而,Add((方法的存在打破了不变性。我想知道,是否有新的方法来实现这个目标?我在StackOverflow上看到了这个问题-我可以使用大括号初始化BCL不可变集合吗?-当时似乎还没有合适的解决方案,但这个问题已经很老了,希望C#中有一些新功能可用?我已经读过关于为不可变对象提供对象初始化的方法引入init修饰符的文章(这里(,但该功能似乎被恢复了。我想也许有一些功能可以使Add((方法只用于初始化?

更新。我可能只需要向不可变集合添加一个构造函数,比如新的MyImmutableCollection(/*items*/(。然而,使用构造函数可能涉及详细的语法,尤其是当您需要为每个元素传递几个参数时。使用构造函数的示例:

var collectionA = new MyImmutableCollection(new (int code, string description)[] {
( 1, "One" ),
( 2, "Two" ),
});

集合初始化语法示例:

var collectionB = new MyImmutableCollection
{
{ 1, "One" },
{ 2, "Two" },
};

集合初始化语法更简洁,因此更可取。

这就是我们需要添加到类中以支持上面的构造和集合初始化语法的内容:

public MyImmutableCollection(IEnumerable<(int code, string description)> collection)
{
// omitted for brevity
}
public void Add(int code, string description)
{
// omitted for brevity
}

你做不到。你可以用这样一种简单的方式来实现它:

class MyImmutableCollection : IEnumerable<MyElement>
{
readonly List<MyElement> list = new List<MyElement>();
public MyImmutableCollection(IEnumerable<MyElement> list)
{
this.list.AddRange(list);
}
private MyImmutableCollection()
{
}
public MyElement this[int index]
{
get { return list[index]; }
}
public IEnumerator<MyElement> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

下面是如何使用:

var list = new List<MyElement> { new MyElement() };
MyImmutableCollection immutableList = new MyImmutableCollection(list);

此外,您还可以添加一个扩展方法:

public static MyImmutableCollection ToImmutableCollection(this IEnumerable<MyElement> elements)
{
MyImmutableCollection list = new MyImmutableCollection(elements);
return list;
}

使用它更简单:

var list = new List<MyElement> { new MyElement() };
list.ToImmutableCollection();

无论如何,您都可以使用库System.Collections.Immutable而无需实现,以下是如何使用它:

ImmutableList.Create(new MyElement());

注意:您可以通过Nuget链接添加https://www.nuget.org/packages/System.Collections.Immutable

最新更新