当返回仅仅是一个私有成员的对象引用时,我们应该如何防御?在某种程度上

本文关键字:我们 对象引用 在某种程度上 何防御 成员 仅仅是 返回 一个 | 更新日期: 2023-09-27 18:05:07

考虑这个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();
        }
    }
}

如果运行此命令,您将得到两行输出:

Your ints are in the correct order and you should stop worrying.
You've failed, your highness.

IntsOwner类的原始设计者想要确保私有成员_ints拥有一个特定的属性(列表元素的排序)。但是,由于对实际对象的引用是通过Ints属性返回的,因此该类的用户可以修改对象,使该属性不再有效。

这类代码在实践中不太可能出现,但是对私有成员的控制以这种方式"泄漏"仍然令人不安。程序员应该在多大程度上阻止这种事情的发生?例如,将Ints属性的表达式体更改为_ints.Select(i = i),从而关闭这种修改私有成员的方式是否合理或相称?或者这会是不必要的偏执,损害代码的可读性吗?

当返回仅仅是一个私有成员的对象引用时,我们应该如何防御?在某种程度上

我总是在ToList后面添加一个AsReadOnly()调用

在返回类型

中,不变性是关键,而不仅仅是最小知识原则

https://msdn.microsoft.com/en-us/library/e78dcd75 (v = vs.110) . aspx

你可以这样做

public IEnumerable<int> Ints => _ints.ToList<int>();

所以你没有返回对_intts的引用,而只是一个复制的列表。任何修改返回值的人都只是在修改他们自己的副本,而不是私有存储的副本。