你可能知道以下问题:你想在两个对象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()复制整个List - 所以我最终得到了同一个集合的x个实例ReadOnlyCollection仅确保客户端不更改集合,但不保证客户端集合不会更改。
实际上这是我经常遇到的情况,因为我写的大多数类(猜测:80-90%)实际上是不可变的,并且通常聚合基本上代表不可变数组的集合(在这种情况下意味着:固定的 - 大小不可变的项目序列)。从我的观点来看,这个问题的一个很好的解决方案很简单:为数组构建一个包装类,保证在构造函数中正确初始化,并且只提供不改变底层数组的方法/属性。
长话短说:对于不可变数组概念的以下(微不足道)实现有什么问题吗?
Btw:我认为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);
}
}
}
答案 0 :(得分:3)
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
}
答案 1 :(得分:2)
IEnumerable
或仅返回yield return
将整个Items.GetEnumerator()
- 代码压缩为几行。
答案 2 :(得分:1)
.NET刚发布了他们的第一个immutable collections,我建议你试试。