C# 集合类型的属性

C# 集合类型的属性,c#,collections,properties,ienumerable,C#,Collections,Properties,Ienumerable,当属性具有某些集合类型时,如 public IList<MyItemClass> MyList{ get; } public IList MyList{get;} IMHO,最好返回空集合而不是空值 有许多方法可以实现这种功能 public IList<MyItemClass> MyList{ get; private set; } public MyClass(){ MyList = new List<MyItemClass>(); } pub

当属性具有某些集合类型时,如

public IList<MyItemClass> MyList{ get; }
public IList MyList{get;}
IMHO,最好返回空集合而不是空值
有许多方法可以实现这种功能

public IList<MyItemClass> MyList{ get; private set; }
public MyClass(){
    MyList = new List<MyItemClass>();
}
public IList MyList{get;private set;}
公共MyClass(){
MyList=新列表();
}
这样可以减少类字段的数量,但需要在每个构造函数中放入代码

private List<MyItemClass> _myList = new List<MyItemClass>();
public IList<MyItemClass> MyList{ get{ return _myList; } }
private List\u myList=new List();
公共IList MyList{get{return\u MyList;}}
这是标准方式。但是,当有人向您的代码中写入某些内容时,他可以使用私有字段而不是属性,并且当您重构get action时,您可能会遇到一些错误

private List<MyItemClass> _myList;
public IList<MyItemClass> MyList{ get{ return _myList??(_myList = new List<MyItemClass>()); } }
private List\u myList;
公共IList MyList{get{return}u MyList???(_MyList=new List());}
这是前一种延迟加载方式的变体

您希望返回什么作为集合的默认值?如果这是空集合,您如何实现它?

选项2(标准方式),并通过确保您的单元测试检查在您期望时返回空列表来避免重构问题。

来自:

务必为所有属性提供合理的默认值,确保默认值不会导致安全漏洞或效率极低的设计

扩展此原则并将其与相结合应该非常清楚地表明,应该始终返回空集合,而不是null

当您可以提供一个合理、直观的默认值时,为什么要将检查null的负担放在调用方身上

封装的全部要点是在一个单一的位置进行工作。它可能会使特定的类实现稍微复杂一些,但它使使用其API变得更简单

在大多数情况下,我将集合实现为包含类型中的不变量:

public class MyClass
{
    private readonly List<Foo> foos;

    public class MyClass()
    {
        this.foos = new List<Foo>();
    }
}
公共类MyClass
{
私有只读列表foos;
公共类MyClass()
{
this.foos=新列表();
}
}
请注意,使用了
readonly
关键字,确保一旦设置,列表就永远不会被替换或清空(但仍然可以重置)。这将保护列表作为类的不变量,从而避免我在其余代码中编写空检查


延迟加载也是一种有效的编码习惯用法,但我只在明确需要时才使用它。

我更喜欢第二种变体,因为它更明显,并且减少了构造函数的大小。 但通常是将此字段设置为只读:

private readonly List<MyItemClass> _myList = new List<MyItemClass>();
private readonly List\u myList=new List();

返回
null
确实不理想。寻找替代方案;这取决于用途。在国际海事组织,这个版本(从主帖子复制)是最简单的,但它做了我们需要的一切:

private List<MyItemClass> _myList = new List<MyItemClass>();
public IList<MyItemClass> MyList { get { return _myList; } }
private List\u myList=new List();
公共IList MyList{get{return\u MyList;}}
作为一个优势,它将与
XmlSerializer
一起工作,而任何带有
私有集的
都不起作用(一个bug;它看到了setter,但没有注意到它不能使用它)


惰性方法通常是杀伤力过大的,因为在大多数有趣的情况下,无论如何都要填充列表。

我通常使用在构造函数中初始化列表的变量。这可能会使构造函数更“臃肿”,但构造函数的责任是构造对象。设置良好的默认值完全在其职责范围内。另外,作为奖励,您不必担心私有字段会使代码看起来更干净

当然,重构确实变得有点困难,但并不明显。不要忘记,您可以链接您的构造函数(大多数情况下都是这样),因此即使您有多个构造函数,您也应该只需要编写一次初始值设定项代码

不过,不要忘记记录默认值是空集合。将集合字段设置为只读是一种良好的做法,除非您有充分的理由在以后重置它