C# 如何避免公共访问私有字段?
例如,让我们声明:C# 如何避免公共访问私有字段?,c#,.net,C#,.net,例如,让我们声明: private readonly List<string> _strings = new List<string>(); public IEnumerable<string> Strings { get { return _strings; } } private readonly List _strings=new List(); 公共IEnumerable字符串 { 得到 { 返回_字符串; }
private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
get
{
return _strings;
}
}
private readonly List _strings=new List();
公共IEnumerable字符串
{
得到
{
返回_字符串;
}
}
现在我们可以做以下工作:
((List<string>) obj.Strings).Add("Hacked");
((列表)对象字符串).Add(“Hacked”);
因此,我们实际上并没有隐藏列表
,而只是将其隐藏在接口后面。在这样的示例中,如何在不复制新集合中的字符串的情况下隐藏列表以限制列表的修改?。这应该可以解决这个问题
private ReadOnlyCollection<string> foo;
public IEnumerable<string> Foo { get { return foo; } }
private ReadOnlyCollection foo;
公共IEnumerable Foo{get{return Foo;}}
只读集合
:
初始化ReadOnlyCollection类的新实例,该类是指定列表周围的只读包装
有很多方法
最简单的方法是始终复制私有字段:
return _strings.ToList();
但这通常不是必要的。不过,如果:
列表,因此您最好返回一个列表(不公开原始列表)
return _strings.AsReadOnly();
这比第一个选项更有效,但将公开对基础集合所做的更改
这些战略也可以结合起来。如果您需要原始集合的副本(因此对原始集合的更改无效),但又不希望返回的对象是可变的*,则可以使用:
// copy AND wrap
return _strings.ToList().AsReadOnly();
您还可以使用收益率:
foreach (string s in _strings)
{
yield return s;
}
这在效率和权衡方面与第一个选项类似,但执行延迟
显然,这里要考虑的关键是如何使用你的方法,以及你要用这个属性提供什么样的功能。
*尽管说实话,我不知道你为什么会在意。除了ReadOnlyCollection
之外,还有真正可用的
使用不可变集合可以向使用者保证集合不会改变,而不仅仅是它们不能改变它们。因为它们是不可变的,所以您可以公开它们:
public ImmutableList<string> Strings { get; private set; }
公共不可变列表字符串{get;private set;}
更多详细信息:您可以将列表包装在getter中,如下所示:
private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings {
get {
return new ReadOnlyCollection<string>(_strings);
}
}
private readonly List _strings=new List();
公共IEnumerable字符串{
得到{
返回新的ReadOnlyCollection(_字符串);
}
}
这样,您就可以在类内自由修改私有列表,而不用担心外部的更改
注意:ReadOnlyCollection
不会复制它包含的列表(例如_字符串)我将向您发布我对封装的最新想法,可能您会发现它们是合理的
众所周知,封装是非常有用的东西,它有助于克服复杂性。它使您的代码在逻辑上简洁明了
正如您所说,对成员的受保护访问可能会被破坏,界面用户可以获得对底层对象的完全访问权。但是有什么问题吗?您的代码不会变得更加复杂或耦合
事实上,据我所知,使用一些反射几乎没有任何限制,即使是完全私有的成员。那你为什么不把它们也藏起来呢
我认为没有必要复制一个集合(或任何其他可变的集合),上面的方法是错误的。使用初始变量:
private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
get
{
return _strings;
}
}
private readonly List _strings=new List();
公共IEnumerable字符串
{
得到
{
返回_字符串;
}
}
由于还没有人给出这个答案,这里有另一个选择:
private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
get { return _strings.Select(x => x); }
}
private readonly List _strings=new List();
公共IEnumerable字符串
{
获取{返回_字符串。选择(x=>x);}
}
它实际上相当于前面提到的yield-return
方法,但更紧凑一些。OP不希望人们访问列表?ReadOnlyCollection
仍然提供对列表的读取权限。我很确定这不是问题所在。如果你不想公开某些东西,你就把它设为私有。我可能弄错了,希望OP能提供进一步的澄清。现在,包含foo
的类可以向它添加项目了吗?我想是的,如果是的话,那么这个答案是错误的,因为它改变了类的内部行为。为什么这个类的“内部行为”是什么?实现细节就是实现细节。仅供参考,不,一旦创建了ReadOnlyCollection
,您就不能再向其中添加项目了。这就是为什么在这里使用IEnumerable
的“只读”是明智的,如果您(令人钦佩)的目标是限制消费者可以执行的操作。如果你决定返回,比如说,一个数组,那么你就不走运了;每次都必须复制一份。@mattytommo:问题不在于字符串会改变。问题是字符串返回的对象本身是可变的。丹的答案是好的,但是这里有一些微妙的地方需要考虑。例如,假设您分发了对某个对象的引用,然后在分发该引用之后,由于类内的某些正确操作,列表的内容发生了更改。这在您的场景中可能吗?如果是,那么先前分发的参考文献是否需要观察变化?也就是说,它的行为是否像可变集合上的不可变外观,还是像快照一样,显示列表的内容与过去一样?@SergeyMetlov保持原样,然后在代码的第二版上,将其从list
更改为类似T[]
,然后观察演员错误开始出现。这教给我们的是如何对接口(或公共契约)而不是实现进行编码