C # - свойства пересчитываются каждый раз, когда к ним обращаются? - PullRequest
6 голосов
/ 18 апреля 2011

Предполагая следующий простой код:

private const int A = 2;
private const int B = 3;


public int Result
    {
        get
        {
            return A * B;
        }
    }

Я часто использую свойство Result.
Продукт A * B пересчитывается каждый раз?

Ответы [ 8 ]

5 голосов
/ 18 апреля 2011

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

Способ кэширования результатов будет

private int? _result;
public int Result {
  get {
     if (!_result.HasValue) {
       _result = A*B;
     }
     return _result.Value;
  }
}

Здесь есть несколько предостережений.

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

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

Третий , если базовые переменные изменили между вызовамиполучатель свойства (т. е. A или B имеет новое значение), тогда NOT будет перерасчитано с этими новыми значениями.

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

3 голосов
/ 18 апреля 2011

В свойствах нет ничего волшебного. Они просто синтаксический сахар по двум методам, get_Xxx и set_Xxx. Зная это, ясно, что каждый раз, когда к свойству обращаются, выполняется весь код внутри get части.

2 голосов
/ 18 апреля 2011

Поскольку значения const, компилятор может оптимизировать эту ситуацию.

Но если они не const, он будет рассчитываться каждый раз.

1 голос
/ 18 апреля 2011

Большинство языков не определяют, как работают оптимизации.Обычная фраза языка-юриста - «как будто», и в этом случае определение C #, скорее всего, скажет «значение свойства при каждом вызове возвращается , как если бы было оценено».Это дает типам компиляторов свободу делать все, что сохраняет задокументированное поведение.

Таким образом, компилятор может оптимизировать это.Обычно компиляторы с длинной историей и акцентом на производительность (C # имеет долгую историю и много ресурсов, а не столько акцент на производительность) пытаются выяснить, при каких обстоятельствах можно повторно использовать ранее вычисленный результат.Тот факт, что ваши A и B объявлены как CONSTS, предполагает, что компилятор может выяснить, что продукт является константой и что фактически он может заменить каждый вызов метода получения на const.

Может.Делает ли это - открытый вопрос.Я сомневаюсь, что Microsoft ответит на этот вопрос «да, это абсолютно так».

1 голос
/ 18 апреля 2011

Да, свойства - это просто специальные методы, которые выполняются при каждом обращении к ним.Если вы хотите кэшировать результаты, сохраните их в переменной-члене, возможно, обнуляемом int, и проверьте, был ли он рассчитан или нет, прежде чем возвращать его (также известный как отложенная инициализация):

int? _result = null;
public int Result {
    get {
        if ( _result == null )
            _result = A * B;
        return _result;
    }
}
1 голос
/ 18 апреля 2011

Да.Тем не менее, хорошее практическое правило заключается в том, что если вам нужна такая операция, это должен быть метод.

0 голосов
/ 18 апреля 2011

Открывая сборку в отражателе, компилятор оптимизирует умножение, так как они const int:

public class FooContainer
{
    private const int A = 2;
    private const int B = 3;


    public int Result
    {
        get
        {
            return A * B;
        }
    }
}

станет:

public class FooContainer
{
    // Fields
    private const int A = 2;
    private const int B = 3;

    // Properties
    public int Result
    {
        get
        {
            return 6;
        }
    }
}

Но если вы измените переменные на просто int и не сохраните вычисление, оценка будет происходить каждый раз.

Пример:

public class FooContainer
{
    private int A = 2;
    private const int B = 3;


    public int Result
    {
        get
        {
            return A * B;
        }
    }
}

становится:

public class FooContainer
{
    // Fields
    private int A = 2;
    private const int B = 3;

    // Properties
    public int Result
    {
        get
        {
            return (this.A * 3);
        }
    }
}
0 голосов
/ 18 апреля 2011

Свойство оценивается каждый раз, когда оно вызывается. Если вы хотите что-то более эффективное, вы должны справиться с этим самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...