是否有可能以某种方式将System.Array标记为不可变。当置于public-get / private-set之后,它们无法添加,因为它需要重新分配和重新分配,但消费者仍然可以设置他们希望的任何下标:

public class Immy
{
    public string[] { get; private set; }
}

我认为readonly关键字可能会成功,但没有这样的运气。

有帮助吗?

解决方案

ReadOnlyCollection<T> 可能正是您所寻找的。它没有Add()方法。

其他提示

框架设计指南建议返回数组的副本。这样,消费者就无法从阵列中更改项目。

// bad code
// could still do Path.InvalidPathChars[0] = 'A';
public sealed class Path {
   public static readonly char[] InvalidPathChars = 
      { '\"', '<', '>', '|' };
}

这些更好:

public static ReadOnlyCollection<char> GetInvalidPathChars(){
   return Array.AsReadOnly(InvalidPathChars);
}

public static char[] GetInvalidPathChars(){
   return (char[])InvalidPathChars.Clone();
}

这些例子直接来自本书。

请参阅 不可变集合现已可用 (目前处于预览状态)。

您可以使用Array.AsReadOnly方法返回。

我认为最佳做法是使用IList <!> lt; T <!> gt;而不是公共API中的数组出于这个原因。 readonly 会阻止在构造函数之外设置成员变量,但正如您所发现的那样,不会阻止人们在数组中分配元素。

请参阅阵列被认为有些有害了解更多信息。

编辑:数组不能只读,但可以通过@shahkalpesh指出的Array.AsReadOnly()转换为只读IList实现。

除了最简单和最传统的用例之外,.NET倾向于远离数组。对于其他一切,有各种可枚举/集合实现。

当您想将一组数据标记为不可变时,您将超越传统数组提供的功能。 .NET提供了相同的功能,但技术上并不是数组的形式。要从数组中获取不可变集合,请使用“> Array.AsReadOnly<T>

var mutable = new[]
{
    'a', 'A',
    'b', 'B',
    'c', 'C',
};

var immutable = Array.AsReadOnly(mutable);

immutable将是“> ReadOnlyCollection<char> 实例。作为更一般的用例,您可以创建“> ReadOnlyCollection<T> “MSDN:System.Collections.Generic.IList ”> IList<T> 实施。

var immutable = new ReadOnlyCollection<char>(new List<char>(mutable));

请注意,它必须是通用实现;普通的旧版 <= > 将无效,这意味着您无法在传统阵列上使用此方法,该阵列仅实现 IList 。这揭示了使用

唯一要添加的是Arrays 暗示可变性。当您从函数返回一个数组时,您建议客户端程序员可以/应该更改内容。

继Matt的回答之后,IList是一个完整的数组抽象接口,所以它允许添加,删除等。我不确定为什么Lippert似乎建议它作为IEnumerable的替代品,需要不变性。 (编辑:,因为IList实现可以为这些变异方法抛出异常,如果你喜欢这样的话)。

也许要记住的另一件事是列表中的项目也可能具有可变状态。如果你真的不希望调用者修改这种状态,你有一些选择:

确保列表中的项是不可变的(如示例所示:string是不可变的)。

返回所有内容的深层克隆,因此在这种情况下,无论如何都可以使用数组。

返回一个可以只读访问项目的界面:

interface IImmutable
{
    public string ValuableCustomerData { get; }
}

class Mutable, IImmutable
{
    public string ValuableCustomerData { get; set; }
}

public class Immy
{
    private List<Mutable> _mutableList = new List<Mutable>();

    public IEnumerable<IImmutable> ImmutableItems
    {
        get { return _mutableList.Cast<IMutable>(); }
    }
}

请注意,可从IImmutable接口访问的每个值本身必须是不可变的(例如字符串),或者是您即时创建的副本。

您可以希望做的最好的事情是扩展现有的集合以构建您自己的集合。最大的问题是它必须以不同于每个现有集合类型的方式工作,因为每次调用都必须返回一个新集合。

您可能需要查看类似的我的回答关于在对象上公开集合的更多想法的问题。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top