У меня есть следующий метод
void DoSome(){
if (int.Parse(SomeStringProperty) > 8)
// do something
if (int.Parse(SomeStringProperty) < 10)
// do something
}
Знает ли JIT, что нужно сохранить проанализированное значение, или лучше сделать следующее:
void DoSome(){
var x = int.Parse(SomeStringProperty);
if (x > 8)
// do something
if (x < 10)
// do something
}
Здесь я вижу две оптимизации:
- JIT автоматически сделает что-то вроде второго примера.
- JIT выполняет одну оптимизацию и кэширует результат
Мой вопрос касается только одной оптимизации, которая должна быть последовательной, а не двух оптимизаций, которые могут зависеть от множества факторов.
Короче говоря, когда я пишу приложение на С#, какой из приведенных выше примеров предпочтительнее?
Обновить
Если ответа нет, то почему он отличается от этого:
foreach (var x in MyMethod.GetEnumeration())
здесь не нужно делать:
var lst = MyMethod.GetEnumeration();
foreach (var x in lst)
Ответ 1 · рейтинг 8 · Marc Gravell
В общем случае нет. Потому что: побочные эффекты. В общем, any.Method(args) может каждый раз делать что-то новое (регистрация, случайный выбор, увеличение счетчиков, подключение к внешнему неуправляемому ресурсу и т. д.) и должен вызываться каждый раз, чтобы сохранить исходную семантику. Может быть, что поддерживается белый список "чистых" функций, но я не вижу особых причин для включения в него int.Parse.
По сути, если вы хотите поднять его: поднимите его сами. Код во втором примере разумен (лично я бы добавил else, то есть else if).
Кроме того: ваш пример вызывает SomeStringProperty несколько раз : это тоже должно вызываться несколько раз, чтобы сохранить семантику, и может вести себя по-разному.
Наконец, в многопоточном мире само поле могло измениться.
Ответ 2 · рейтинг 1 · Marc Gravell
Об обновлении: этот пример совершенно не связан. Вы также можете привести пример:
var val = MyMethod.SomeMethod();
и сравните его с:
var tmp = MyMethod.SomeMethod();
var val = tmp;
в обоих случаях все, что вы сделали, это отделили вызов/оценку от использования путем присваивания промежуточной переменной. И в обоих случаях, если мы предположим, что переменная lst / tmp больше нигде не используется, мы можем быть достаточно уверены, что компилятор (не JIT) в любом случае действительно удалит эту переменную, так что они не просто логически эквивалентны - они фактически эквивалентны. В этом сценарии мы не удаляли никаких вызовов методов и т. д. - мы оцениваем их только один раз. Совершенно не связанный сценарий.