【发布时间】:2020-09-21 01:45:56
【问题描述】:
我只是偶然发现了以下问题:
class Settings
{
// Let's set some default value: { 1 }
public ICollection<int> AllowedIds = new List<int>() { 1 };
}
static void Main(string[] args)
{
var s = new Settings
{
AllowedIds = { 1, 2 }
};
Console.WriteLine(string.Join(", ", s.AllowedIds)); // prints 1, 1, 2
}
我明白为什么会这样:AllowedIds = { 1, 2 } 不是一个赋值,而是一个对象初始化器中的集合初始化器,也就是说,它是一个AllowedIds.Add(1); AllowedIds.Add(2)的隐式调用。
不过,对我来说这是一个陷阱,因为它看起来像一个作业(因为它使用了=)。
作为一名 API/库开发人员(假设我是开发 Settings 类的人)想要遵守 principle of least surprise,我可以做些什么来阻止我的库的消费者不会掉进那个陷阱?
脚注:
在这种特殊情况下,我可以使用
ISet/HashSet<int>而不是ICollection/List(因为重复对AllowedIds没有意义),这将产生1, 2的预期结果。尽管如此,初始化AllowedIds = { 2 }会产生1, 2的反直觉结果。我在C# github repo上找到了一个相关的讨论,基本上得出的结论是,是的,这个语法很混乱,但它是一个旧特性(2006年引入),我们不能改变它而不向后打破兼容性。
【问题讨论】:
-
哇。这是一个惊喜。我怀疑除了在文档中提到它之外,您无能为力,但话又说回来,我在这里可能错了。
-
这令人惊讶。我以前从未注意到这一点。
标签: c# api-design collection-initializer least-astonishment