.net - .net 中的不可变数组 (c#) : Reasonable approach?

标签 .net arrays immutability

你可能知道以下问题:你想在两个对象 A 和 B 之间共享一个集合(或者类似地想通过属性公开一个集合)并且......好吧,你意识到这实际上不是一个好主意因为 A 和 B 都可以修改集合,现在等等等等世界末日......

但您常常会意识到,您不想将集合作为一个整体来共享,而只想使用集合中的项初始化一个对象,或者将这些项传递给对象的方法。此外,对象的项目在对象的生命周期内不会改变,因此您通常最终会做这样的事情:

public class Foo
{
  private List<int> items;

  public Foo(IEnumerable<int> items)
  {
    this.items = items.ToList();
  }

  public ReadOnlyCollection<int> Items
  {
    get { return new ReadOnlyCollection(this.items); }
  }
}

.ToList() 和 ReadonlyCollection-Wrapper 都为该问题提供了合理的解决方案,但它们也遇到了一些问题:.ToList() 复制了整个列表 - 所以我最终得到了同一个集合的 x 个实例,而ReadOnlyCollection 仅确保客户端不会更改集合,但不向客户端提供集合不会更改的任何保证。

实际上,这是我经常遇到的情况,因为我编写的大多数类(猜测:80 - 90 %)实际上是不可变的,并且经常聚合基本上代表不可变数组的集合(在这种情况下意味着:一个固定的-大小不可变的项目序列)。从我的角度来看,这个问题的一个很好的解决方案非常简单:为数组构建一个包装类,保证在构造函数中正确初始化,并只提供不改变底层数组的方法/属性。

长话短说:以下不可变数组概念的(微不足道的)实现有什么问题吗?

顺便说一句:我认为 Sequence 是一个合适的名称,因为 a) 它很好地描述了意图(一个固定大小的不可变项目序列) b) 它不是 .net 当前使用的名称,并且 c) 它非常短,这很重要,因为我打算广泛使用它。

public sealed class Sequence<T> : IEnumerable<T>
    {
        private readonly T[] items;

        public Sequence(IEnumerable<T> items)
        {
            this.items = items.ToArray();
        }

        public Sequence(int size, Func<int, T> producer)
        {
            this.items = new T[size];

            for (int i = 0; i < size; i++)
            {
                this.items[i] = producer(i);
            }
        }

        public T this[int i]
        {
            get { return this.items[i]; }
        }

        public int Length
        {
            get { return this.items.Length; }
        }

        public bool Contains(T item)
        {
            for (int i = 0; i < this.items.Length; i++)
            {
                if (this.items[i].Equals(item))
                    return true;
            }

            return false;
        }

        public Enumerator<T> GetEnumerator()
        {
            return new Enumerator<T>(this);
        }

        IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator()
        {
            return GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public struct Enumerator<T> : IEnumerator<T>
        {
            private T[] items;
            private int nextIndex;
            private T current;

            internal Enumerator(Sequence<T> immutableArray)
            {
                this.items = immutableArray.items;
                this.nextIndex = 0;
                this.current = default(T);
            }

            public T Current
            {
                get { return this.current; }
            }

            object System.Collections.IEnumerator.Current
            {
                get { return this.Current; }
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                if (this.nextIndex < this.items.Length)
                {
                    this.current = this.items[this.nextIndex];
                    this.nextIndex++;
                    return true;
                }
                else
                {
                    return false;
                }
            }

            public void Reset()
            {
                this.nextIndex = 0;
                this.current = default(T);
            }
        }
    }

最佳答案

您的 Sequence 类会给您什么 ReadOnlyCollection 没有的?难道不能只使用简单的继承来提供所需的构造函数吗?

public class Sequence<T> : ReadOnlyCollection<T>
{
    public Sequence(IEnumerable<T> items)
        : base(items.ToList()) { }

    public Sequence(int size, Func<int, T> generator)
        : base(Enumerable.Range(0, size).Select(generator).ToList()) { }

    // properties, methods etc provided by the ReadOnlyCollection base class
}

关于.net - .net 中的不可变数组 (c#) : Reasonable approach?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1432937/

相关文章:

.net - 从非托管 C++ 动态加载混合模式 C++/CLI .dll(和依赖项)

.net - 使用 apachesoap :Map complex datatype in webservice using .net

java - Android JSON解析Json数组是[]在解析时抛出空指针异常,如何以正确的方式编写?

java - 我对 Java 2d 数组的内存分配是错误的还是运行时发生了什么?

ruby - 最简洁的方法,采用单级散列参数并返回具有 nil 值的副本

java - 使类不可变的另一种方法

C# 到 VB .NET yield 返回转换

c# - unicode 字符代码的 uint 和 char 转换

delphi - Delphi 中的高效缓存

java - jackson 反序列化绕过最终领域