C# 当返回的对象引用仅仅是一个以某种方式“模糊”的私有成员时,应该如何防御?
考虑一下这个C程序:C# 当返回的对象引用仅仅是一个以某种方式“模糊”的私有成员时,应该如何防御?,c#,casting,ienumerable,defensive-programming,C#,Casting,Ienumerable,Defensive Programming,考虑一下这个C程序: using System; using System.Collections.Generic; using System.Linq; namespace SandboxApplication { public class IntsOwner { private List<int> _ints; public IntsOwner (IEnumerable<int> ints) {
using System;
using System.Collections.Generic;
using System.Linq;
namespace SandboxApplication
{
public class IntsOwner
{
private List<int> _ints;
public IntsOwner (IEnumerable<int> ints)
{
_ints = ints.OrderBy(i => i).ToList(); // They must be in the correct order
}
public IEnumerable<int> Ints
=> _ints;
public void CheckFirstTwoInts ()
{
if (_ints.Count < 2)
{
Console.WriteLine("You need to collect some more ints before trying this.");
}
else if (_ints[0] <= _ints[1])
{
Console.WriteLine("Your ints are in the correct order and you should stop worrying.");
}
else
{
Console.WriteLine("You've failed, your highness.");
}
}
}
class Program
{
static void Main (string[] args)
{
var intsOwner = new IntsOwner(new List<int> {1, 2, 3, 4, 5});
var ienumerable = intsOwner.Ints;
var list = (List<int>)ienumerable;
intsOwner.CheckFirstTwoInts();
list[0] = 6;
intsOwner.CheckFirstTwoInts();
Console.ReadLine();
}
}
}
IntsOwner类的原始设计者希望确保列表元素的特定属性顺序适用于私有成员_int。但是,由于对实际对象的引用是通过Ints属性返回的,因此该类的用户可以修改该对象,使该属性不再有效
这类代码在实践中似乎不太可能出现,但仍然令人不安的是,对私有成员的控制可能会以这种方式泄漏。程序员应该在多大程度上阻止这类事情呢?例如,将Ints属性的表达式体更改为_Ints.Selecti=i,从而关闭这种修改私有成员的方式是否合理或相称?或者,这会对代码的可读性造成不必要的偏执吗?您可以这样做
public IEnumerable<int> Ints => _ints.ToList<int>();
因此,您不会返回对_int的引用,而只返回一个复制的列表。任何修改返回值的人都只会修改他们自己的副本,而不是私人存储的副本 我总是在ToList之后添加对AsReadOnly的调用 不变性是关键,而不仅仅是返回类型中知识最少的原则
即使是私有的_int也可以修改,这是因为调用公共属性get时传递了对它的引用。为了保护私有列表,解决方案似乎是通过属性返回该列表的副本,但是如何控制有效的更改?这不是一个容易解决的问题,甚至不是必须解决的问题。我想我不会为此担心。向列表转换是对内部信息的显式使用——它距离通过反射获取私有成员仅一步之遥。很明显,您通过类的公共接口仅公开只读信息。顺便说一句,通过.Net中的反射,我们可以访问所有成员、方法、属性等,而不管它们的私有范围如何,这使得这些注意事项变得过时。您只能保护这么多人。您的职责是提供一个供他们使用的接口。无论你想做什么,人们都可以用反射来四处走动。如果他们试图将您的IEnumerable强制转换为一个列表,如果他们有足够的决心,他们将管理它。您是否将此数据发送到UI或web应用程序,然后从客户端获取ID以在后端执行某些操作?基本上,我想澄清一下,如果您询问的是安全软件编码实践。OP知道这一点,他提到了类似的解决方案_ints.Selecti=I。他在问这是否必要/是个好主意。
public IEnumerable<int> Ints => _ints.ToList<int>();