当前位置: 首页 > 编程语言 > C#

正确暴露List?正确分享

时间:2023-04-10 13:00:37 C#

公共列表?我知道我不应该在属性中公开列表,但我想知道正确的方法是什么?例如,这样做:publicstaticclassClass1{privatereadonlystaticList_list;publicstaticIEnumerableList{get{return_list;//返回_list.AsEnumerable();行为相同}}staticClass1(){_list=newList();_list.Add("一个");_list.Add("两个");_list.Add("三个");}}允许我的调用者简单地转换回列表:privatevoidbutton1_Click(objectsender,EventArgse){vartest=Class1.ListasList;test.Add("四");//这确实修改了Class1._list,这很糟糕?}所以如果我想要一个真正不可变的列表,我总是想创建一个新列表?例如,这似乎有效(转换后测试null):publicstaticIEnumerableList{get{returnnewReadOnlyCollection(_list);但我担心是否存在性能开销,因为每次有人尝试访问它时我的列表都会被克隆?使用AsReadOnly()-有关详细信息,请参阅MSDN将列表公开为属性实际上并不是万恶之源;特别是如果它允许像foo.Items.Add(...)这样的预期用途。您可以编写AsEnumerable()替代方案:publicstaticIEnumerableAsSafeEnumerable(thisIEnumerabledata){foreach(Titemindata)yieldreturnitem;但目前你最大的问题是线程安全。作为静态成员,您可能会遇到大问题,尤其是当它是ASP.NET之类的东西时。甚至现有列表上的ReadOnlyCollections也会受此影响:Listints=newList{1,2,3};varro=ints.AsReadOnly();Console.WriteLine(ro.Count);//3个整数。加法(4);Console.WriteLine(ro.Count);//4所以简单地用AsReadOnly包装它不足以让你的对象线程安全;它只是阻止消费者添加数据(但是当你的其他线程添加数据时,他们仍然可以枚举它,除非你同步或复制)。是和不是。是的,因为创建了一个新对象,所以会有性能开销。不,您的列表未被克隆,它被ReadOnlyCollection包装。如果该类没有其他用途,您可以从列表继承并重写add方法并让它抛出异常。您不必担心克隆的开销:用ReadOnlyCollection包装集合不会克隆它。它只是创建一个包装器;如果基础集合发生变化,只读版本也会发生变化。如果您担心一遍又一遍地创建新的包装器,您可以将它们缓存在一个单独的实例变量中。之前问过类似的问题:基于此,我建议你在内部使用List,并使其成为Collection或IList。或者,如果您只想要枚举而不是像这样添加或修改IEnumerable。关于能够将你返回的东西转换为其他东西的问题,我只想说不要打扰。如果人们想以非预期的方式使用您的代码,他们将能够以某种方式使用。我之前也问过一个关于这个的问题,我想说唯一明智的做法是公开你想要的东西,如果人们以不同的方式使用它,那是他们的问题:p一些相关的问题:如果你公开列表作为IEnumerable,我不会担心调用者回滚到列表。您已在类的合同中明确声明此列表中只允许在IEnumerable中定义的操作。因此,您已隐含声明该列表的实现可能会更改为实现IEnumerable的任何内容。当您的枚举在中间并且修改了集合时,AsEnumerable和ReadOnlyCollection会出现问题。这些东西不是线程安全的。最好将它们作为数组返回并在调用时缓存它们。比如上面是C#学习教程:ProperlyexposeList?如果分享的内容对你有用,需要了解更多C#学习教程,希望大家多多关注——publicstaticString[]List{get{return_List.ToArray();}}//同时使用...String[]values=Class1.List;foreach(stringvinvalues){...}//而不是调用foreach(stringvinClass1.List)//一次又一次,此上下文中的值不会被//复制,但是值是cachedinstanceso//立即更改将不可用,但其//线程安全foreach(stringvinvalues){...}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: