我非常注重C ++思维,需要针对特定C#问题提供一些指导。我们假设我们有以下类:
public class Foo
{
private IList<Bar> _bars = new List<Bar>(); // Note IList<> vs List<>.
public IList<Bar> Bars
{
get { return _bars; }
set
{
...
}
}
}
现在,取代...
,我倾向于清除_bars
和AddRange
set
参数value
中的项目,而不是只需将value
分配给_bars
即可。我看待它的方式是,我希望继续引用value
项引用的相同项,而不是IList<Bar>
引用的实际value
。< / p>
这是错误的想法吗?你觉得怎么样?
编辑:经过一些评论后,我意识到我必须补充一点,我希望能够在Foo ctor中使用现有的Bars集合并从该集合中初始化_bars。所以,到目前为止,通过该修订和评论,这感觉更好:
public class Foo
{
private readonly List<Bar> _bars = new List<Bar>();
public Foo(IEnumerable<Bar> bars)
{
_bars.AddRange(bars);
}
public IList<Bar> Bars
{
get { return _bars; }
}
}
它更好吗?
答案 0 :(得分:8)
如果我们讨论的是业务(域)对象,我会公开IEnumerable<T>
以及适合该集合的任何方法,通常是Add,Remove和Clear。我几乎从不公开收藏品的制定者。
答案 1 :(得分:3)
是否有必要使您的Foo实例的Bars属性引用另一个List?
如果没有,那么我宁愿没有酒吧的属性设置器。
如果有必要将Bars属性设置为另一个List实例,那么我想我发现你的setter修改了列表会很奇怪。 我的意思是:当我为该属性分配另一个Bars列表时,我会假设我的Foo实例然后包含我已分配给该属性的列表中可用的Bars。不多也不少。 我会发现很奇怪,突然发现该集合包含更多(或更少)的条...
答案 2 :(得分:3)
根据您提问的推断要求:
public class Foo
{
private readonly IList<Bar> _bars = new List<Bar>();
public IList<Bar> Bars
{
get { return _bars; }
}
}
答案 3 :(得分:2)
当然,不需要为Bars属性公开setter。在内部,您持有对集合的引用,Kent建议可以将其标记为Readonly。通过getter,调用者可以使用可用方法(Add,Remove,Clear,AddRange等)对集合执行他们想要的操作,但至关重要的是,他们永远不能更改您对集合对象持有的内部引用。
然后,您可以控制允许的方法。正如Jamie所建议的那样,拥有属性返回类型IEnumerable
会导致Bars属性暴露一个只读集合。公开IList
表示可以修改集合的内容。酒店的安装人员可以将其打开,让来电者做他们想做的事,而且你不再受控制。
修改强>
按照上面的问题编辑。这实际上取决于Foo
对象的使用方式。
由于您主要关注的是从现有Foo
个对象列表中初始化Bar
...
IList<Bar> bars = ...some list of Bars previously constructed...
Foo
的最新代码示例强制调用者通过构造函数初始化,但也允许他们通过属性更改集合
Foo foo = new Foo(bars);
...
foo.Bars.Clear();
foo.Bars.AddRange(bars);
当允许通过构造函数初始化对象时,您需要问自己为什么要这样做。是吗......
您需要问自己 - 您是否希望调用者能够在构建Foo
对象后更改Bars集合的内容?
如果否 - 使Bars属性公开一个只读集合
如果是 - 向Foo
对象添加默认构造函数,以便调用者不必提供列表来初始化它。但如果他们通过重载构造函数选择,他们可以选择这样做。
答案 4 :(得分:1)
我对这些属性的setter很好,但我通常不允许空值,因为null很少有空的列表具有不同的商业含义。
set { _bars = value ?? new List<Bar>();}
答案 5 :(得分:0)
我认为从getter返回_bars引用有点狡猾。你真的希望班级的客户能够修改列表的内容吗?
所以我会做以下事情:在构造/设置上复制并返回getter的只读视图。