1

我正在编写一个接口,它有一个我想只读的集合属性。我不希望界面的用户能够修改集合。我发现创建只读集合属性的典型建议是将属性的类型设置为 IEnumerable,如下所示:

private List<string> _mylist;
public IEnumerable<string> MyList
{
get
    {
        return this._mylist;
    }
}

然而,这并不能阻止用户将 IEnumerable 转换回 List 并对其进行修改。

如果我使用Yield关键字而不是_mylist直接返回,这会阻止我界面的用户修改集合。我是这么认为的,因为那时我只是一个一个地返回对象,而不是实际的集合。

 private List<string> _mylist;
public IEnumerable<string> MyList
{
get
    {
        foreach(string str in this._mylist)
        {
            yield return str;
        }
    }
}
4

5 回答 5

5

这是防止您的类的用户转换回列表和访问成员的合理方法。另一种选择是使用 _mylist。AsReadOnly(),它返回一个ReadOnlyCollection<T>.

但是,我建议不要担心用户如何通过转换为其他内部类型来“破坏”您的 API。IEnumerable<T>如果您放置List<T>. 试图阻止用户做一些不恰当的事情并像这样破坏你的 API 充其量是有问题的,特别是因为你不能阻止所有不恰当的使用。

于 2010-05-03T23:28:13.277 回答
4

是的,它是不可变的。

但是,您应该使用 aReadOnlyCollection<string>代替。

例如:

MyClassName() {  //(Constructor)
    MyList = new ReadOnlyCollection<string>(_myList);
}

private List<string> _mylist;
public ReadOnlyCollection<string> MyList { get; private set; }
于 2010-05-03T23:26:38.357 回答
3

是的,这行得通。但这不是唯一的方法。这是在 .NET 3.5 中工作的另一种方式:

public IEnumerable<string> MyList
{
    get { return _myList.Skip(0); }
}

取自这个问题,该问题还显示了您可以做到的其他一些方法。

(使用谷歌找到)。

于 2010-05-03T23:27:39.500 回答
1

如果使用你的类的代码完全信任,它总是可以反射和访问私有字段。这将是相当不礼貌的,但铸造返回值只是稍微好一点。如果用户投射您的财产并破坏状态,那么这样做是他们自己的错。

将列表实例直接返回为 IEnumerable 的一个优点是 LINQ 可以优化对 ElementAt() 或 Count() 等方法的访问,而不会违反 IEnumerable 的基本约定(因为两者都可以通过枚举来完成)。

于 2010-05-04T01:14:03.567 回答
0

是的,生成的序列将是只读的。它还具有延迟执行的优点,因此在某些客户端代码枚举序列中的项目之前不会实际评估循环(尽管如果在客户端代码尝试枚举之前更改内部集合,这可能会产生意想不到的后果) .

于 2010-05-03T23:25:37.750 回答