Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.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#_Casting_Ienumerable_Defensive Programming - Fatal编程技术网

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) {

考虑一下这个C程序:

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>();