ReadonlyCollection, являются ли объекты неизменяемыми?

Я пытаюсь использовать ReadOnlyCollection, чтобы сделать объект неизменным, я хочу, чтобы свойство объекта было неизменным.

public ReadOnlyCollection<FooObject> MyReadOnlyList
{
    get
    {
        return new ReadOnlyCollection<FooObject>(_myDataList);
    }
}

Но я немного растерялся.

Я попытался изменить свойство объекта на MyReadOnlyList с помощью foreach и... Я могу изменить значение свойства, это правильно? Я понял, что ReadOnlyCollection установил уровень добавления, чтобы сделать объект неизменным.

3 ответа

Решение

Дело в том, что ReadOnlyCollection является неизменным означает, что коллекция не может быть изменена, т.е. никакие объекты не могут быть добавлены или удалены из коллекции. Это не значит, что объекты, которые он содержит, неизменны.

Эта статья Эрика Липперта объясняет, как работают различные виды неизменности. В основном, ReadOnlyCollection неизменный фасад, который может читать основную коллекцию (_myDataList), но не может изменить его. Однако вы все равно можете изменить базовую коллекцию, так как у вас есть ссылка на _myDataList делая что-то вроде _myDataList[0] = null,

Кроме того, объекты, возвращаемые ReadOnlyCollection те же самые, возвращенные _myDataListт.е. this._myDataList.First() == this.MyReadOnlyList.First()LINQ). Это означает, что если объект в _myDataList изменчив, то и объект в MyReadOnlyList,

Если вы хотите, чтобы объекты были неизменными, вы должны разработать их соответствующим образом. Например, вы можете использовать:

public struct Point
{
    public Point(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }

    // In C#6, the "private set;" can be removed
    public int X { get; private set; }
    public int Y { get; private set; }
}

вместо:

public struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

Редактировать: в этом случае, как отмечает Ian Goldby, ни одна структура не позволяет изменять свойства элементов в коллекции. Это происходит потому, что структуры являются типами значений, и когда вы обращаетесь к элементу, коллекция возвращает копию значения. Вы можете изменить только свойства Point введите, если это класс, что будет означать, что возвращаются ссылки на реальные объекты, а не копии их значений.

Я попытался изменить свойство объекта на MyReadOnlyList с помощью foreach и... Я могу изменить значение свойства, это правильно? Я понял, что ReadOnlyCollection установил уровень добавления, чтобы сделать объект неизменным.

Используя ReadOnlyCollection не дает никаких гарантий относительно объекта, который хранится в коллекции. Все это гарантирует, что коллекция не может быть изменена после ее создания. Если элемент извлекается из него, и он имеет изменяемые свойства, он может быть очень хорошо изменен.

Если вы хотите сделать свой FooObject неизменный, тогда просто сделайте так:

public class FooObject
{
    public FooObject(string someString, int someInt)
    {
        SomeString = someString;
        SomeInt = someInt;
    }

    public string SomeString { get; };
    public int SomeInt { get; };
}

Неизменным является сама коллекция, а не предметы. На данный момент C# не поддерживает неизменяемые объекты, не оборачивая их как ReadOnlyCollection<T> делает в вашем случае.

Ну, вы все равно можете создавать неизменяемые объекты, если их свойства не имеют доступного установщика. Кстати, они вовсе не являются неизменяемыми, потому что они могут видоизменяться от члена класса, который может иметь равную или большую доступность, чем установщик.

// Case 1
public class A
{
    public string Name { get; private set; }

    public void DoStuff() 
    {
        Name = "Whatever";
    }
}

// Case 2
public class A
{
    // This property will be settable unless the code accessing it
    // lives outside the assembly where A is contained...
    public string Name { get; internal set; }
}

// Case 3
public class A
{
    // This property will be settable in derived classes...
    public string Name { get; protected set; }
}

// Case 4: readonly fields is the nearest way to design an immutable object
public class A
{
     public readonly string Text = "Hello world";
}

Как я уже говорил, ссылочные типы всегда изменяемы по определению, и они могут вести себя как неизменяемые при определенных условиях, играющих с доступностью членов.

Наконец, структуры являются неизменяемыми, но они являются типами значений, и их не следует использовать только потому, что они могут представлять неизменные данные. См. Этот раздел вопросов и ответов, чтобы узнать больше о том, почему структуры неизменны: почему структуры C# неизменны?

Другие вопросы по тегам