支持不可变集合的集合初始化语法 - 方法的初始化修饰符?
Supporting collection initialization syntax for immutable collections - init modifiers for methods?
我需要实现一个支持集合初始化语法的不可变集合。问题是为了支持集合初始化语法,集合必须提供适当的 public Add() 方法。但是,如果集合提供 public Add() 方法,它就不再是不可变的。
我想要实现的示例:
var element = new MyElement();
var collection1 = new MyImmutableCollection { element };
var collection2 = new MyImmutableCollection { "ABC" };
为了让它工作,我需要 MyImmutableCollection 来实现 IEnumerable 并为 Add() 方法提供适当的签名(更多关于集合初始化的信息是 here):
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() 方法的存在破坏了不变性。请问有没有什么新的方法可以达到目的呢?我在 Whosebug 上看到了这个问题 - Can I initialize a BCL immutable collection using braces? - and seems like at that moment there was no appropriate solution, but that question is quite old, and hopefully there are some new features available in C#? I've read about introduction of init modifiers for methods to provide object initialization for immutable objects (here), but seems like the feature 。我想也许有一些功能可以使 Add() 方法仅用于初始化?
更新。我可能只向不可变集合添加一个构造函数,例如 new MyImmutableCollection( /* items */ )。但是,使用构造函数可能涉及冗长的语法,尤其是当您需要为每个元素传递多个参数时。使用构造器的例子:
var collectionA = new MyImmutableCollection(new (int code, string description)[] {
( 1, "One" ),
( 2, "Two" ),
});
集合初始化语法示例:
var collectionB = new MyImmutableCollection
{
{ 1, "One" },
{ 2, "Two" },
};
集合初始化语法更简洁,因此更可取。
这就是我们需要添加到 class 以支持上面的构造和集合初始化语法的内容:
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添加linkhttps://www.nuget.org/packages/System.Collections.Immutable
我需要实现一个支持集合初始化语法的不可变集合。问题是为了支持集合初始化语法,集合必须提供适当的 public Add() 方法。但是,如果集合提供 public Add() 方法,它就不再是不可变的。
我想要实现的示例:
var element = new MyElement();
var collection1 = new MyImmutableCollection { element };
var collection2 = new MyImmutableCollection { "ABC" };
为了让它工作,我需要 MyImmutableCollection 来实现 IEnumerable 并为 Add() 方法提供适当的签名(更多关于集合初始化的信息是 here):
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() 方法的存在破坏了不变性。请问有没有什么新的方法可以达到目的呢?我在 Whosebug 上看到了这个问题 - Can I initialize a BCL immutable collection using braces? - and seems like at that moment there was no appropriate solution, but that question is quite old, and hopefully there are some new features available in C#? I've read about introduction of init modifiers for methods to provide object initialization for immutable objects (here), but seems like the feature
更新。我可能只向不可变集合添加一个构造函数,例如 new MyImmutableCollection( /* items */ )。但是,使用构造函数可能涉及冗长的语法,尤其是当您需要为每个元素传递多个参数时。使用构造器的例子:
var collectionA = new MyImmutableCollection(new (int code, string description)[] {
( 1, "One" ),
( 2, "Two" ),
});
集合初始化语法示例:
var collectionB = new MyImmutableCollection
{
{ 1, "One" },
{ 2, "Two" },
};
集合初始化语法更简洁,因此更可取。
这就是我们需要添加到 class 以支持上面的构造和集合初始化语法的内容:
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添加linkhttps://www.nuget.org/packages/System.Collections.Immutable