为List属性实现setter(在C#中)写入时是一件坏事:
private List<string> _TheList = new List<string>();
public List<string> TheList
{
get { return _TheList; }
set { _TheList = value; }
}
不应该写成:
private List<string> _TheList = new List<string>();
public List<string> TheList
{
get { return _TheList; }
set { _TheList = new List<string>(value); }
}
直到今天我通常使用前者,但我最近发现了一些使用后者的代码,似乎这可能是实现这一目的的正确方法。
在对分配给它的外部列表进行更改时,不使用前者会导致更改TheList属性。例如:
List<string> list = new List<string>();
list.Add("Hello");
var c = new someClass();
c.TheList = list;
使用前者不会破坏TheList的封装:
list.Clear();
现在c.TheList也是空的,这可能不是我们想要的。但是,使用后一种方法,c .List不会被清除。
答案 0 :(得分:7)
Collection properties should be readonly
Your property should expose a Collection<T>
, not a List<T>
编辑:解释:
如果其他代码复制对列表的引用(例如,var list = Thingy.TheList
),如果将属性设置为其他列表,则可能会混乱。 (它最终会持一个孤儿)
通常,很少有理由允许人们将属性指向不同的集合实例。
使用Collection<T>
代替List<T>
可以拦截对集合的更改并添加验证或维护父字段。 (通过继承Collection<T>
并覆盖InsertItem
和其他方法)您甚至可以在shippinga库之后添加此类逻辑,而不会破坏调用代码。
答案 1 :(得分:6)
我相信由于列表是一个参考对象,您需要做的就是获取引用。所以:
private List<string> _TheList = new List<string>();
public List<string> TheList
{
get { return _TheList; }
}
获得引用并对集合进行更改后,您将更改_TheList
答案 2 :(得分:3)
这完全取决于您希望您的财产如何运作。如果您想要副本,请复制。否则,不要。通常,像这样的属性根本不会暴露出一个setter,因为替换整个列表对于那种情况来说不是一个理想的动作。
当然,使用第二种方法可能会带来性能上的缺陷,因为属性语法隐藏了每次使用setter时都完全复制并创建新列表的事实。
答案 3 :(得分:0)
首先,两者都有些不正确。公共属性应该真正公开为IList,因为List是特定于实现的(当使用List作为公共属性时,fxcop实际上会警告你。)
其次,如果可能的话,我会将setter设为私有。使用getter,用户仍然可以添加/删除/清除/等。但是简化了你在问题中提出的问题。
答案 4 :(得分:0)
我认为你的问题没有普遍的答案。您描述的行为可能是也可能不是您想要的。
总的来说,我同意SLaks认为将集合属性保持为只读是更清晰,但这完全取决于
答案 5 :(得分:0)
我不确定我是否理解正确。但我这样做:
c.TheList = list.ToArray().ToList();