好的,据我了解,不可变类型本质上是线程安全的,所以我已经在很多地方读过,我想我理解为什么会这样。如果一旦创建对象便无法修改实例的内部状态,则并发访问实例本身似乎没有问题。

因此,我可以创建以下List:

class ImmutableList<T>: IEnumerable<T>
{
    readonly List<T> innerList;

    public ImmutableList(IEnumerable<T> collection)
    {
         this.innerList = new List<T>(collection);
    }

    public ImmutableList()
    {
         this.innerList = new List<T>();
    }

    public ImmutableList<T> Add(T item)
    {
         var list = new ImmutableList<T>(this.innerList);
         list.innerList.Add(item);
         return list;
    }

    public ImmutableList<T> Remove(T item)
    {
         var list = new ImmutableList<T>(this.innerList);
         list.innerList.Remove(item);
         return list;
    } //and so on with relevant List methods...

    public T this[int index]
    {
        get
        {
            return this.innerList[index];
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return innerList.GetEnumerator();
    }

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

所以问题是:这真的是不可变的类型吗?它真的是线程安全的吗?

显然,类型本身是不可变的,但是T绝对没有保证,因此您可能会遇到与通用类型直接相关的并发访问和线程问题。那是否意味着ImmutableList应该被认为是可变的?
class ImmutableList<T>: IEnumerable<T> where T: struct是否应该是唯一真正被认为是不可变的类型?

感谢您对此问题的任何投入。

更新:很多答案/评论都集中在我发布的ImmutableList的特定实现上,这可能不是一个很好的例子。但是问题的关键不是实现。我要问的问题是,考虑到不可变类型需要的所有内容,ImmutableList<MutableT>是否真的是不可变类型。

最佳答案



通常是这样,是的。



简要总结一下:可变列表周围有一个写时复制包装器。向不可变列表中添加新成员不会使该列表发生变化。相反,它会制作基础可变列表的副本,将其添加到副本中,然后返回围绕该副本的包装器。

假设要包装的基础列表对象在读取时不会改变其内部状态,则您已满足“不可变”的原始定义,因此,是的。

我注意到这不是实现不可变列表的非常有效的方法。例如,使用不可变的平衡二叉树可能会做得更好。每次创建新列表时,草图在时间和内存上均为O(n);您可以毫不费力地将其改进为O(log n)。



前提是基础可变列表对于多个读取器是线程安全的,是的。

您可能对此感兴趣:

http://blogs.msdn.com/b/ericlippert/archive/2011/05/23/read-only-and-threadsafe-are-different.aspx



这是一个哲学问题,而不是技术问题。如果您有一个不可变的人名列表,并且列表从未更改,但是其中一个人死亡,那么名称列表是否为“可变”?我不会。

如果有关列表的任何问题始终具有相同的答案,则列表是不可变的。在我们的姓名列表中,“列表上有几个姓名?”是关于列表的问题。 “有多少人还活着?”不是关于 list 的问题,而是关于 list 所指的人的问题。这个问题的答案会随着时间而改变。第一个问题的答案不是。



我没有关注你。将T限制为结构如何改变什么? OK,T仅限于struct。我做了一个不变的结构:

struct S
{
    public int[] MutableArray { get; private set; }
    ...
}

现在我制作一个ImmutableList<S>。是什么让我无法修改存储在S实例中的可变数组?仅仅因为列表是不可变的,而struct是不可变的,则不能使数组不可变。

关于c# - 一成不变还是不一成不变?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9009627/

10-11 21:40