我用??我的代码非常重视运算符。但今天我刚遇到一个问题。
这里我用的代码是什么?操作
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()而在其他我正在做新的List()。
答案 0 :(得分:6)
我看到的唯一区别是,在第一种情况下,您的变量_names将包含一个新的空列表,而在第二种情况下它不包含。在这两种情况下,返回的值都是相同的。
答案 1 :(得分:3)
在第二种情况下,如果_names
为空,则不会将new List<string>()
分配给_names
,每次拨打Names
时,它都会创建new List<string>()
,但是第一个案例new List<string>()
创建一个。
答案 2 :(得分:2)
它会在两种情况下返回相同的值,但不同之处在于,如果您在私有函数中的任何位置访问_names,则_names在第一种情况下将具有空列表,但在第二种情况下将为空值。因此,根据编码标准,第一个实现是正确的,在第二种情况下,您可能会面临零异常问题。
答案 3 :(得分:2)
正如其他人所说,区别在于检索属性后字段_names
的状态。
get { return _names ?? (_names = new List<string>()); }
如果_names
为空,则会创建并分配新的List<string>
。在此之后,对属性Names
的每次检索都将返回刚刚创建的列表。
get { return _names ?? new List<string>(); }
如果_names
为空,则会返回新的List<string>
。与案例1相比,它不会被分配给任何东西。这意味着每次时间检索Names
,将创建并返回一个新列表。
话虽这么说,你应该对这段代码的两个版本都非常小心。在get
中分配值不一定是好事。懒惰地实例化属性值很方便,并且在你是唯一使用该类的人的情况下可以接受,但它的风格很差。您班外的任何用户都不希望get
设置任何内容......这是属性set
部分的用途。从长远来看,只需返回_names
并在默认构造函数中实例化它就会更好。然后它清楚代码正在做什么,并且您获得了保证的非null属性值。
对于第二种情况,你远更好地返回null并允许用户处理它。请考虑以下情况,其中items
是一个大型对象集合,每个对象都包含您的属性Names
,无论出于何种原因,Names
始终为null:
foreach (var item in items.Where(x => x.Names != null)) {
Console.WriteLine(String.Join(", ", item.Names));
}
如果您只是返回null,则会跳过整个块。但是,由于每次都返回一个新列表,不仅是你在整个循环中运行而且基本上什么也没做,你在每次迭代时都要实例化一个新列表!在某些条件下,这可能会非常昂贵。