Каковы недостатки этого шаблона для обеспечения неизменности?

Учитывая следующий класс:

public static class ComboModel
{
    public static Dictionary<int, int[]> Items()
    {
        return new Dictionary<int, int[]>
        {
            {
                1, 
                new[] { 
                    2,
                    3,
                    4  
                }
            }
        };
    }
}

Я хочу обеспечить неизменность данных в классе, но это похоже на javascript и вызвало некоторую расплывчатую (но сильную) критику со стороны моих коллег. Что с этим не так?


person Chris McCall    schedule 31.03.2016    source источник
comment
Выглядит действительно странно.   -  person Mateen Ulhaq    schedule 31.03.2016
comment
Ну, он выделяет каждый раз, когда вызывается метод. Может быть, вместо этого просто использовать ImmutableDictionary?   -  person vcsjones    schedule 31.03.2016
comment
Он также использует много строк в буфере редактора;)   -  person Dai    schedule 31.03.2016
comment
Создание словарей стоит дорого, поэтому инициализируйте его один раз. Также верните IReadOnlyDictionary‹› вместо Dictionary. Это должно открыть некоторые возможности для рефакторинга.   -  person Trevor Ash    schedule 31.03.2016
comment
В вашем вопросе не совсем указано, что является неизменным. Это сам словарь, вы хотите быть неизменным, или вы просто хотите возвращать свежий, но изменяемый словарь каждый раз, когда вызывается Items(), который вызывающая сторона может изменять самостоятельно?   -  person vcsjones    schedule 31.03.2016


Ответы (1)


Просто используйте ReadOnlyDictionary и выделите его только один раз:

public static class ComboModel {
    private static readonly ReadOnlyDictionary<int, int[]> _items = new ReadOnlyDictionary<int, int[]>(new Dictionary<int, int[]> {
        {
            1,
            new[] {
                2,
                3,
                4
            }
        }
    });

    public static IReadOnlyDictionary<int, int[]> Items
    {
        get { return _items; }
    }
}

Обратите внимание, что вы не только выделяете новый экземпляр при каждом вызове, как уже упоминалось другими, но вы также даете вызывающему абоненту неправильное ощущение, что он может изменить этот словарь. В ReadOnlyDictionary нет методов, которые могут его модифицировать. Есть и другие преимущества, когда вызывающая сторона знает, что полученная структура не может быть изменена: например, он может безопасно обрабатывать элементы в нескольких потоках.

Обновление: конечно, коллекции только для чтения волшебным образом не делают объекты, хранящиеся в этих коллекциях, доступными только для чтения - только сама коллекция. Если вы хотите обеспечить неизменность массивов int[] в своем примере, просто сделайте их доступными только для чтения:

public static class ComboModel {
    private static readonly IReadOnlyDictionary<int, ReadOnlyCollection<int>> _items = new ReadOnlyDictionary<int, ReadOnlyCollection<int>>(new Dictionary<int, ReadOnlyCollection<int>> {
        {
            1,
            Array.AsReadOnly(new[] {
                2,
                3,
                4
            })
        }
    });

    public static IReadOnlyDictionary<int, ReadOnlyCollection<int>> Items
    {
        get { return _items; }
    }
}
person Evk    schedule 31.03.2016
comment
Вы можете ошибаться в отношении вводящего в заблуждение названия ReadOnlyDictionary stackoverflow.com /вопросы/32438988/ - person Chris McCall; 31.03.2016
comment
То есть вы хотите сделать не только словарь, но и все массивы значений доступными только для чтения? - person Evk; 31.03.2016
comment
Я считаю, что смысл в том, чтобы остановить кого-либо, изменяющего данные в базовом классе, и поэтому возврат словаря, который позволяет изменять значения в нем, нарушает это. - person Tim Rutter; 31.03.2016
comment
Обновленный ответ с исправлением, предотвращающим это. - person Evk; 01.04.2016
comment
Но вы все равно можете установить любое значение равным нулю или присвоить ему новый объект, тем самым изменив данные в классе. ImmutableDictionary - это то, что нужно, поскольку создает копию. - person Tim Rutter; 01.04.2016
comment
@afragonabike Я думаю, что вы не можете установить для ключа значение null или новый объект в ReadOnlyDictionary - просто нет установщика. То же самое для ReadOnlyCollection — вы не можете изменять элементы в нем. - person Evk; 01.04.2016