使用 ReadOnlyCollection 和 Getter

Using ReadOnlyCollection and a Getter

昨天我问了一个关于深度克隆列表的问题,我得到了一个很好的答案,你可以阅读

我遇到的问题是答案使用 ImmutableList 我对此没有任何问题,只是如果我想使用 ReadOnlyCollection 并且 确保我 return 我的 collection 的副本,class 中的副本无法修改。

我只是想知道以下是否正确。

    private ReadOnlyCollection<Author> listofAuthors;   
    private List<Author> copyofAuthors;

    public Book(ICollection<Author> authors)
    {

        copyofAuthors = new List<Author>(authors);
        listofAuthors = new ReadOnlyCollection<Author>(new List<Author>(copyofAuthors));

    }

    public ICollection<Author> Authors
    {
        get
        {
            return new ReadOnlyCollection<Author>(new List<Author>(copyofAuthors));
        }
    }

根据 MSDN documentation ReadOnlyCollection 只是底层可变 collection 的包装器。因此,如果对基础 collection 进行任何更改,它将反映在 ReadOnlyCollection 中。上面的代码 getter return 是一个只读的新列表 collection。

问题 1:

鉴于上述代码,调用它的任何其他代码将获得 private ReadOnly(new List()) 的 副本,对吗?用户所做的任何更改都不会反映在 Book class 内的 ReadOnlyCollection 中,对吗?

问题 2:

我理解 ImmutableList 更理想,但是如果我需要使用 ReadOnlyCollection<Authors> 我在 Constructor/Getter 中所做的是否正确?还是可以用another/better方式实现?

考虑以下 class:

public Book(ICollection<Author> origAuthors)
{
    // We only need to allocate the ReadOnlyCollection once.
    this.Authors = new ReadOnlyCollection<Author>( new List<Author>( origAuthors ) );

}

public ICollection<Author> Authors { get; private set; }

在此代码中,origAuthors 存储了一组对 Author 对象的引用。该集合可由提供它的任何人修改。我还假设 Author 是 class 而不是结构,因此具有引用语义。

此代码复制了对 Author 对象的引用列表,用 ReadOnlyCollection 实例包装该列表,并通过我们的 [=19= 公开该 ReadOnlyInstance 实例] 属性.

由于Book.Authors属性最终指的是作者列表的副本,如果我们从origAuthors中删除一个元素,那么Book.Authors将不会反映它;它将保留以前的作者集。

例如:

void Test() {
    List<Author> mutableAuthors = new List<Author>();
    mutableAuthors.AddRange( ... add 5 authors ... );

    Book testBook = new Book( mutableAuthors );
    mutableAuthors.Clear();

    // Prints 5.
    Console.Writeline( testBook.Authors.Count );

    // Throws an exception from ReadOnlyCollection.
    testBook.Authors.Clear();
}

但是,到目前为止,我们所讨论的只是一组引用 Author 对象的列表;我们还没有与 Author 对象本身交谈。它们是可变的吗?

如果是这样,无论人们如何检索对作者的引用,他们都可能修改作者对象本身。使用 ReadOnlyCollection<Author> 只会阻止您修改列表中的项目;它不会阻止您修改项目本身。

考虑以下代码:

void Test() {
    List<Author> mutableAuthors = new List<Author>();
    mutableAuthors.AddRange( ... add 5 authors ... );

    Book testBook = new Book( mutableAuthors );
    mutableAuthors.Clear();

    // Prints 5.
    Console.Writeline( testBook.Authors.Count );

    Author someAuthor = testBook.Authors[0];
    someAuthor.ChangeName("A new name");

    // Prints "A new name".
    Console.WriteLine( testBook.Authors[0] );
}

如果您想防止这种情况发生,请确保您的作者设计 class 是不可变的 - 一旦构建完成,就不要为消费者提供任何修改它的方法。