列出属性设置器

时间:2010-12-09 16:46:25

标签: c# list encapsulation

为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不会被清除。

6 个答案:

答案 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();