如何避免公共访问私有领域?

Ser*_*lov 24 .net c#

例如,让我们声明:

private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
    get
    {
        return _strings;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以做到以下几点:

((List<string>) obj.Strings).Add("Hacked");
Run Code Online (Sandbox Code Playgroud)

所以我们实际上并没有隐藏List使用方法,只是将其隐藏在界面后面.如何隐藏这个例子中的列表而不复制_strings新的集合来限制列表的修改?

Dan*_*Tao 35

有很多方法.

最天真的方法是始终复制私有字段:

return _strings.ToList();
Run Code Online (Sandbox Code Playgroud)

但这通常不是必需的.这是有意义的,不过,如果:

  1. 你碰巧知道调用代码通常会想要一个List<T>,所以你也可以给一个回来(不暴露原文).
  2. 即使随后更改了原始集合,对于公开的对象来说保持原始值也很重要.

或者,您可以只公开一个只读包装器:

return _strings.AsReadOnly();
Run Code Online (Sandbox Code Playgroud)

这比第一个选项更有效,但会公开对底层集合所做的更改.

这些策略也可以结合起来.如果您需要原始集合的副本(因此对原始集合的更改没有效果)但也不希望返回的对象是可变的*,您可以使用:

 // copy AND wrap
return _strings.ToList().AsReadOnly();
Run Code Online (Sandbox Code Playgroud)

你也可以使用yield:

foreach (string s in _strings)
{
    yield return s;
}
Run Code Online (Sandbox Code Playgroud)

这与第一个选项的效率和权衡相似,但延迟执行.

显然,这里要考虑的关键是如何实际使用您的方法以及您提供此属性的具体功能.

*虽然说实话,但我不确定你为什么要关心.

  • 你也可以使用`Select(x => x)`,这将最终创建一个新的迭代器,从而防止它被强制转换回`List`. (3认同)

Tej*_*rma 7

如何使用ReadOnlyCollection.这应该解决这个特殊问题.

private ReadOnlyCollection<string> foo;
public IEnumerable<string> Foo { get { return foo; } }
Run Code Online (Sandbox Code Playgroud)

  • 我很确定这不是问题所在.如果您不想公开地公开某些内容,则将其设为私有 (2认同)

ast*_*tef 5

我会发布你关于封装的最新想法,也许你会发现它们合理.

众所周知,封装是非常有用的东西,它有助于对抗复杂性.它使您的代码在逻辑上简约明了.

正如您所说,可以破坏对成员的受保护访问,并且界面用户可以获得对底层对象的完全访问权限.但问题是什么呢?您的代码不会变得更复杂或耦合.

实际上,据我所知,使用一些反思几乎没有任何限制,即使有完全私人成员.那你为什么不试着隐藏它们呢?

我认为没有必要复制一个集合(或任何其他可变的)和上面的方法是错误的.使用您的初始变体:

private readonly List<string> _strings = new List<string>();
public IEnumerable<string> Strings
{
    get
    {
        return _strings;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Tejas我总是有理论上可以修改我记忆中的任何对象.特别是,管理.这就是为什么银行应用程序依赖于在线身份验证,事务验证等而不是客户端应用程序中的特定集合类型 (4认同)