使用YIELD是一种只读方式来返回一个集合吗?

时间:2010-05-03 23:23:34

标签: c# .net properties yield-keyword

我正在编写一个具有集合属性的接口,我想要只读它。我不希望界面的用户能够修改集合。我发现创建只读集合属性的典型建议是将属性的类型设置为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;
        }
    }
}

5 个答案:

答案 0 :(得分:5)

这是一种合理的方法,可以防止您的类用户返回到List并访问成员。另一种选择是使用_mylist。AsReadOnly(),它返回ReadOnlyCollection<T>

但是,我建议不要担心用户如何通过转换为其他内部类型来“破解”您的API。如果您放置IEnumerable<T>的公共API,则这是最终用户将(或应该)使用的 - 而不是尝试强制转换为List<T>。试图阻止用户做一些不合适的事情并破坏你的API就好了,特别是因为你无法阻止所有不恰当的用法。

答案 1 :(得分:4)

是的,它是不可改变的。

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

例如:

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

private List<string> _mylist;
public ReadOnlyCollection<string> MyList { get; private set; }

答案 2 :(得分:3)

是的,这很有效。这不是唯一的方法。这是另一种适用于.NET 3.5的方法:

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

取自question,其中还显示了其他一些方法。

(使用Google找到)。

答案 3 :(得分:1)

如果使用您的类的代码具有完全信任,则无论如何都可以反映并访问私有字段。这将是相当不礼貌的,但铸造返回值只是稍微好一点。如果用户强制转换你的属性并破坏状态,那么这就是他们自己的错误。

直接将列表实例作为IEnumerable返回的一个好处是LINQ可以优化对ElementAt()或Count()等方法的访问,而不会违反IEnumerable的基本契约(因为任何一个也可以通过枚举来实现)。

答案 4 :(得分:0)

是的,生成的序列将是只读的。它还具有延迟执行的优点,因此在某些客户端代码枚举序列中的项之前,实际上不会对循环进行求值(尽管如果在客户端代码尝试枚举内部集合之前更改内部集合,则会产生意外后果)