Установщики свойств .Net когда-либо вызывались неявно?

Я работаю над проектом ASP.Net 2.0 в C #. У меня есть некоторые данные, которые хранятся в состоянии сеанса. Для простоты использования оно заключено в свойство, например:

protected IList<Stuff> RelevantSessionData
{
    get
    {
        return (IList<Stuff>) Session["relevant_key"];
    }
    set
    {
        Session["relevant_key"] = value;
    }
}

Получение и установка значения работает точно так, как вы ожидаете. Если я хочу очистить значение, я просто устанавливаю его на ноль, и нет никаких проблем. Однако на странице другого разработчика он вызывает метод Clear () коллекции. Я думал, что это будет ошибка, но, кажется, работает, и я не понимаю, почему. Это работает так:

Debug.WriteLine(RelevantSessionData.Count);    //outputs, say, 3
RelevantSessionData.Clear();
Debug.WriteLine(RelevantSessionData.Count);    //outputs 0

Почему это работает? Мое наивное ожидание состояло бы в том, что средняя строка загружает сериализованное значение из сеанса, десериализуется в объект, вызывает Clear() для этого объекта, а затем позволяет безымянному объекту выпасть из области видимости. Это было бы ошибкой, потому что значение, сохраненное в Session, останется неизменным. Но, очевидно, он достаточно умен, чтобы вместо этого вызывать установщик свойств и сериализовать вновь измененную коллекцию обратно в сеанс.

Это заставляет меня немного нервничать, потому что в нашем унаследованном коде есть места, где у установщиков свойств есть побочные эффекты, и я не хочу, чтобы те вызывались, если он не предназначен.

Всегда ли вызывается установщик свойств в такой ситуации? Что-то еще происходит? Или я полностью неправильно понимаю, что здесь происходит?

[Добавлено для объяснения ответа]
Оказывается, неправильно поняли. Я знал, что объекты, хранящиеся в Session, должны быть сериализуемыми, и на основании этого я сделал слишком много предположений о том, как коллекция ведет себя внутренне. Я задумался.

Существует только один экземпляр хранимого объекта (my IList). Каждый вызов получателя возвращает ссылку на тот же экземпляр. Таким образом, приведенный выше код работает так же, как и кажется, без особой магии.

И чтобы ответить на заглавный вопрос: Нет, сеттеры не называются неявно.

10
задан Auraseer 27 January 2010 в 16:23
поделиться

3 ответа

Да, вы правы, это было бы ошибкой, если ваши сеттера / Getters были сериализация / десериализация объекты. Но это не так. Вместо этого вы проходите на основе ссылки.

Так что в основном происходит, это то, что первая строка в вашем примере получает элемент через GET, а количество называется на основе этого. Затем линия Seccond выходит и вызывает снова, возвращая один и тот же объект, прозрачный, а затем третья строка делает то же самое, что и первая.

Если вы написали свой сеттер / Getter что-то подобное, у вас будет «ошибка»

protected IList<Stuff> RelevantSessionData
{
    get
    {
        return (IList<Stuff>) JSON.ConvertFromString(Session["relevant_key"]);
    }
    set
    {
        Session["relevant_key"] = JSON.ConvertToString(value);
    }
}

в этом случае, будет создан новый объект, и для каждого вызова на блок Get. Но поскольку ваш пример выше просто передается по ссылке на тот же объект, вы не увидите эту «ошибку».

И я говорю «BUG», так как это не совсем ошибка, это просто более недопонимание того, что происходит за кулисами.

Я надеюсь, что это поможет.

4
ответ дан 4 December 2019 в 04:01
поделиться

Вы можете ожидать вызывающих сопутников, если:

  • - это общедоступно (видно для других собраний).
  • Они реализуют сеттер как часть интерфейса, видимого для других сборок. В некоторых случаях, таких как
  • , они используются в связывании WPF (но структура будет следовать правилам BindingMode ).
  • Они используются в МЭФ с Importattribute .
  • Они используются в некоторых других системах связывания (вы получаете идею).

Вы не должны столкнуться с проблемами, если для интерфейсов, определенных другими, вы соответствуете предварительному и постусловию операции.

Редактировать: Я согласен с вышеупомянутым. Мой первый выбор для разоблачения коллекции:

private readonly List<T> _sources = new List<T>();

/* Or ICollection<T>, ReadOnlyCollection<T>, or IList<T>, or
 * (only a real option for `internal` types) List<T>
 */
public IEnumerable<T> Sources
{
    get
    {
        return _sources;
    }
}

Если вы абсолютно должен инициализировать список после создания объекта, то вы можете использовать что-то вроде этого как второе вариант:

public IList<T> Sources
{
    get;
    private set;
}

Есть ситуации, где Вышеуказанные практики не обязательно являются лучшим ответом, но это два наиболее распространенных (IMO?).

-1
ответ дан 4 December 2019 в 04:01
поделиться

Ваш код примерно эквивалентен:

Debug.WriteLine(((IList<Stuff>) Session["relevant_key"]).Count);    //outputs, say, 3
((IList<Stuff>) Session["relevant_key"]).Clear();
Debug.WriteLine(((IList<Stuff>) Session["relevant_key"]).Count);    //outputs 0

Даже если вы звоните только на Getter, вы очищаете коллекцию. Таким образом, вывод отладки кажется нормальным.

1
ответ дан 4 December 2019 в 04:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: