Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何允许在私有集合上进行迭代,但不允许修改?_C#_Design Patterns_Iterator - Fatal编程技术网

C# 如何允许在私有集合上进行迭代,但不允许修改?

C# 如何允许在私有集合上进行迭代,但不允许修改?,c#,design-patterns,iterator,C#,Design Patterns,Iterator,如果我有以下班级成员: private List<object> obs; 我想允许遍历这个列表作为类接口的一部分,我该怎么做 将其公开是行不通的,因为我不想直接修改列表。您是否考虑过从System.Collections.ReadOnlyCollectionBase派生类?您会将其公开为IEnumerable,而不仅仅是直接返回它: public IEnumerable<object> Objects { get { return obs.Select(o =>

如果我有以下班级成员:

private List<object> obs;
我想允许遍历这个列表作为类接口的一部分,我该怎么做


将其公开是行不通的,因为我不想直接修改列表。

您是否考虑过从System.Collections.ReadOnlyCollectionBase派生类?

您会将其公开为IEnumerable,而不仅仅是直接返回它:

public IEnumerable<object> Objects { get { return obs.Select(o => o); } }
因为您表示只希望遍历列表,所以这就是您所需要的

您可能会试图直接将列表作为IEnumerable返回,但这是不正确的,因为您可以在运行时轻松地检查IEnumerable,确定它是一个列表,并将其强制转换为这样的列表,并改变内容

但是,通过使用return obs.Selecto=>o;最终返回列表的迭代器,而不是对列表本身的直接引用

有些人可能认为,根据C语言规范第7.15.2.5节,这符合退化表达式的条件。然而

此外,人们建议人们使用。这是不正确的,因为保留了原始列表的参考标识。从文件的备注部分:

AsEnumerable IEnumerable方法的作用只是将源代码的编译时类型从实现IEnumerable的类型更改为IEnumerable本身。
换句话说,它所做的只是将源参数强制转换为IEnumerable,这无助于保护引用完整性,原始引用将被返回,并可以回溯到列表中,用于修改列表。

考虑到复制操作的性能损失,您可以使用或复制列表并返回它。您还可以使用。

公开只读集合

您可以通过以下两种方式执行此操作:

private List<object> objs;

public ReadOnlyCollection<object> Objs {
    get {
        return objs.AsReadOnly();
    }
}
通过将列表转换为只读集合:

new System.Collections.ObjectModel.ReadOnlyCollection<object>(this.obs)

关于这个问题的有趣帖子和对话框:。

在您的界面上添加以下方法签名: 公共IEnumerable遍历列表

实施如下:

public IEnumerable<object> TraverseTheList()
{

    foreach( object item in obj)
    {
      yield return item;
    }


}

yield返回告诉编译器为您构建一个枚举器。

这已经说过了,但我不认为任何答案是超级清晰的

最简单的方法是简单地返回ReadOnlyCollection

private List<object> objs;

public ReadOnlyCollection<object> Objs {
    get {
        return objs.AsReadOnly();
    }
}
这样做的缺点是,如果以后要更改实现,则某些调用方可能已经依赖于集合提供随机访问这一事实。因此,更安全的定义是只公开IEnumerable

public IEnumerable<object> Objs { 
    get {
        return objs.AsReadOnly();
    }
}
请注意,编译此代码不必调用AsReadOnly。但如果您不这样做,调用方my只需将返回值转换回列表并修改您的列表

// Bad caller code
var objs = YourClass.Objs;
var list = objs as List<object>;
list.Add(new object); // They have just modified your list.
这种解决方案也存在同样的潜在问题

public IEnumerable<object> Objs { 
    get { 
        return objs.AsEnumerable(); 
    } 
}
所以我强烈建议您在列表中调用AsReadOnly,并返回该值。

只需返回一个


让发问者四处打听并不是什么问题。Google上的第一个结果表明了如何公开ReadOnlyCollection。我只承认@Mitch Wheat应该包含一个指向MSDN页面的链接。如果继续,我们只会复制MSDN页面上的内容。简单+安全的完美组合。请注意,如果代码中出现了选择,我们永远不会优化掉显式调用。在将查询表达式转换为方法调用时,我们将优化掉要选择的隐式调用。如果你说从y中的x选择x,没有选择调用,只有一个where。但若你们说从x到y选择x,那个么我们不仅仅生成y,我们还对它生成一个选择调用,以确保结果的不变性。
public IEnumerable<object> Objs { 
    get { 
        return objs.AsEnumerable(); 
    } 
}
private List<object> obs;

IReadOnlyCollection<object> GetObjects()
{
    return obs;
}