【问题标题】:Properties should not return arrays属性不应返回数组
【发布时间】:2015-12-03 12:04:41
【问题描述】:

是的,我知道这个问题之前已经讨论过很多次了,我阅读了所有关于这个问题的帖子和 cmets,但似乎仍然无法理解。

MSDN 提供的解决此违规问题的选项之一是返回一个 collection(或由 collection实现的 interface >) 访问属性时,但很明显它并不能解决问题,因为大多数集合都不是不可变的,也可以更改。

我在这个问题的答案和 cmets 中看到的另一种可能性是用 ReadOnlyCollection 封装数组并返回它或它的基本接口(如 IReadOnlyCollection),但我不明白如何这解决了性能问题。

如果在任何时候引用该属性,它需要为封装数组的新ReadOnlyCollection 分配内存,那么有什么区别(在性能问题上,不是编辑数组/集合)而不是简单地返回原始数组的副本?

此外,ReadOnlyCollection 只有一个带有IList 参数的构造函数,因此需要在创建数组之前用列表包装数组。

如果我有意在我的类中使用一个数组(而不是作为不可变集合),当我为 ReadOnlyCollection 分配新内存并用它封装我的数组而不是返回数组的副本时,性能会更好吗?

请澄清这一点。

【问题讨论】:

标签: c# arrays .net


【解决方案1】:

如果在任何时候引用该属性,它都需要为封装数组的新 ReadOnlyCollection 分配内存,那么与简单地返回一个副本有什么区别(在性能问题上,不编辑数组/集合)原始数组?

A ReadOnlyCollection<T> 包装集合 - 它不会复制集合。

考虑:

public class Foo
{
    private readonly int[] array; // Initialized in constructor

    public IReadOnlyList<int> Array => array.ToArray(); // Copy
    public IReadOnlyList<int> Wrapper => new ReadOnlyCollection<int>(array); // Wrap
}

假设您的数组包含一百万个条目。考虑Array 属性必须完成的工作量——它必须获取所有百万条目的副本。考虑Wrapper 属性必须完成的工作量 - 它必须创建一个仅包含引用的对象。

此外,如果您不介意额外的内存占用,您可以改为执行一次:

public class Foo
{
    private readonly int[] array; // Initialized in constructor
    private readonly IReadOnlyList<int> Wrapper { get; }

    public Foo(...)
    {
        array = ...;
        Wrapper = new ReadOnlyCollection<int>(array);
    }
}

现在访问 Wrapper 属性根本不涉及任何分配 - 如果 所有 调用者看到相同的包装器也没关系,因为他们无法改变它。

【讨论】:

    【解决方案2】:

    你不需要复制一个数组,只需返回它为IReadOnlyCollection&lt;T&gt;:

      public class MyClass {
        private int[] myArray = ...
    
        public IReadOnlyCollection<int> MyArray {
          get {
            return myArray;
          }
        }
      }
    

    【讨论】:

    • 我刚刚测试了几乎相同的代码,因为它看起来很明显(所以也许我遗漏了一些东西)。也许担心有人会强行将 IReadOnlyColelction 强制转换为数组并随后对其进行修改?不过我不担心,好像有人愿意,他可以用反射直接弄乱私有字段...
    • 如果调用者转换回int[](或只是IList&lt;int&gt;)然后对其进行变异,那就不好了。对于内部 API 来说可能没问题,但我不会在公共 API 中这样做,因为其他代码可能希望依赖不改变的内容。
    • 这个技巧是怎么起作用的? int[] 在继承树的哪个位置继承自 IReadOnlyCollection?显然它有效,但这种铸造怎么可能?它是在哪里定义的?
    猜你喜欢
    • 2021-02-16
    • 1970-01-01
    • 2011-12-10
    • 2020-03-09
    • 2011-08-02
    • 2018-03-29
    • 1970-01-01
    • 2020-10-28
    • 2018-10-18
    相关资源
    最近更新 更多