C# возвращает ссылки на словарь безопасно

Я рассматриваю три подхода для возврата ссылок на внутренние экземпляры словаря (C#) в отношении безопасности кода и влияния на читаемость кода / визуально для проекта, над которым я работаю.

Я сузил это до следующих трех подходов, но я открыт для лучших предложений. В настоящее время я предпочитаю № 3 как лучший баланс безопасности без дополнительной плиты котла.

1) Используйте второй экземпляр ReadOnlyDictionary для переноса внутреннего словаря, только позволяя ReadOnlyDictionary экранировать класс:

2) Возвратите экземпляр Dictionary как IReadOnlyDictionary, но повторное преобразование позволит изменить его так, чтобы оно не было таким безопасным, как вариант № 1 или № 3.

3) Возвращать Dictionary.ToImmutableDictionary() как ImmutableDictionary, когда он выходит за пределы содержащего класса, так что возвращаемый объект является неизменным представлением внутреннего словаря, хотя это будет делать новую копию для каждого вызова, вызывающего более высокую стоимость, что должно быть хорошо с небольшими простыми словарями (которые мои).

    private readonly Dictionary<string, string> innerDictionary = new Dictionary<string, string>();

    // Only required for Example #1
    private readonly IReadOnlyDictionary<string, string> readonlyInnerDictionary;

    public ExampleClass() {
        // Only required for Example #1
        readonlyInnerDictionary = new ReadOnlyDictionary<string, string>(innerDictionary);
    }   

    public IReadOnlyDictionary<string, string> GetExampleOne() {
        // Requires a second dictionary which is more boiler plate but the object being returned is truly readonly
        return readonlyInnerDictionary;     
    }

    public IReadOnlyDictionary<string, string> GetExampleTwo() {
        // Requires InnerDictionary be defined as Dictionary (Not IDictionary) but doesn't require the second dictionary be defined
        // which is less boiler plate, but the object returned could be re-cast to it's mutable form meaning it's not truly mutation safe.
        return innerDictionary;
    }

    public ImmutableDictionary<string, string> GetExampleThree() {
        // Truly immutable object returned, but a new instance is built for every call; fortunately all of my dictionaries are small (containing at most 9 keys)
        return innerDictionary.ToImmutableDictionary();
    }

2 ответа

Решение

Определили, что самое приятное, самое простое и безопасное; но не самым эффективным решением является использование ConcurrentDictionary внутренне, что обеспечивает безопасность резьбы (от System.Collections.Concurrent), а затем использовать System.Collections.Immutable звонить dictionary.ToImmutableDictionary() который создает словарь, который избегает внутреннего класса. Подпись интерфейса для ImmutableDictionary<KeyType, ValueType>,

Это не самое эффективное решение, но в моем случае со словарями с менее чем 12 ключами и небольшими простыми объектами, представляющими состояние, в большинстве случаев это не проблема.

Вариант 1 - это путь. Вы можете преобразовать ReadOnlyDictionary в IDictionary, но это вызовет исключение при попытке изменить:

 void CastingTest()
        {
            var dic1 = new Dictionary<string, string>();
            dic1.Add("Key", "Value");
            var dic2 = new ReadOnlyDictionary<string, string>(dic1);
            var castedDic = (IDictionary<string, string>)dic2;
            castedDic.Add("AnotherKey", "Another Value"); //System.NotSupportedException, Collection is read only
        }

ReadOnlyDictionary не создает другой словарь. Он указывает на ту же ссылку на первый, инкапсулируя его. Так что если вы делаете:

void AddTest()
        {
            var dic1 = new Dictionary<string, string>();
            dic1.Add("Key", "Value");
            var dic2 = new ReadOnlyDictionary<string, string>(dic1);
            dic1.Add("Key2", "Value2"); //Now dic2 have 2 values too.
        }

Никогда не выставляйте свой innerDictionary, и все будет в порядке.

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