3

我用 ??运算符在我的代码中非常重要。但是今天我刚刚遇到一个问题。

这是我用于的代码??操作员

private List<string> _names;
public List<string> Names
{
    get { return _names ?? (_names = new List<string>()); }
}

但在某些地方,我也看到了这段代码。

private List<string> _names;
public List<string> Names
{
    get { return _names ?? new List<string>(); }
}

这些代码之间的真正区别是什么。在一个中,我正在分配 _names = new List(),而在另一个中,我只是在做 new List()。

4

4 回答 4

6

我看到的唯一区别是,在第一种情况下,您的变量 _names 将包含一个新的空列表,而在第二种情况下则不包含。在这两种情况下,返回的值都是相同的。

于 2013-09-10T05:41:41.447 回答
3

在第二种情况下,如果为null,则每次调用时都不会使用 create分配_names,但在第一种情况下会创建。new List<string>()_namesNamesnew List<string>()new List<string>()

于 2013-09-10T05:40:43.237 回答
2

它在两种情况下都将返回相同的值,但不同之处在于,如果您在私有函数中的任何位置访问 _names,则在第一种情况下,_names 将有一个空列表,而在第二种情况下则为空值。因此,根据编码标准,第一个实现是正确的,在第二种情况下,您可能会遇到空异常的问题。

于 2013-09-10T06:10:28.937 回答
2

正如其他人所说,不同之处_names在于检索属性后字段的状态。

情况1

get { return _names ?? (_names = new List<string>()); }

如果_names为 null,List<string>则将创建并分配一个新的。在此之后,每次检索该属性Names都将返回刚刚创建的列表。

案例2

get { return _names ?? new List<string>(); }

如果_names为空,List<string>将返回一个新的。与案例 1 相比,它不会被分配给任何东西。这意味着每次检索时Names,都会创建并返回一个新列表。


话虽如此,您应该非常小心这段代码的两个版本。在 a in 中赋值get不一定是件好事。懒惰地实例化属性值很方便,并且在您是唯一使用该类的人的情况下可能是可以接受的,但它的风格很差。您班级以外的任何用户都不会期望 aget设置任何内容……这就是set属性的一部分。_names从长远来看,在默认构造函数中返回并实例化它总是会更好。然后很清楚代码在做什么,并且您获得了保证的非空属性值。

对于第二种情况,您最好返回 null 并允许用户处理它。考虑以下情况,其中items是一个大型对象集合,每个对象都包含您的属性Names,并且无论出于何种原因,其中Names始终为空:

foreach (var item in items.Where(x => x.Names != null)) {
    Console.WriteLine(String.Join(", ", item.Names));
}

如果您只是返回 null,则将跳过整个块。但是,由于您每次都返回一个新列表,因此您不仅要运行整个循环并且基本上什么都不做,而且每次迭代都会实例化一个新列表!在某些条件下,这可能会变得非常昂贵。

于 2013-09-10T06:29:44.257 回答