В чем преимущество использования локальной переменной? - PullRequest
0 голосов
/ 04 мая 2018

Я постоянно смотрю примеры в Интернете, где в методе есть свойство элемента, которое перед использованием копируется в локальную переменную. Например, что-то вроде этого (из StackPanel исходного кода Microsoft):

UIElementCollection children = arrangeElement.InternalChildren;

...

for (int i = 0, count = children.Count; i < count; ++i)
{
    UIElement child = (UIElement)children[i];
    if (child == null) { continue; }

    ...
}

Может ли кто-нибудь объяснить мне, в чем заключается польза от этого (если он есть), вместо прямого доступа к свойству каждый раз, как это?

for (int i = 0, count = arrangeElement.InternalChildren.Count; i < count; ++i)
{
    UIElement child = (UIElement)arrangeElement.InternalChildren[i];
    if (child == null) { continue; }

    ...
}

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

double value = GetValueFromLongRunningMethod();

...

for (int i = 0; i < someCollection.Count; i++) DoSomethingWith(value);

Но я вижу, что это сделано со свойствами, и удивляюсь, почему. Вот еще один распространенный пример из интернета, касающийся виртуализации:

IItemContainerGenerator generator = this.ItemContainerGenerator;
GeneratorPosition position = generator.GeneratorPositionFromIndex(firstVisibleItemIndex);

Почему вместо этого?:

GeneratorPosition position = 
    this.ItemContainerGenerator.GeneratorPositionFromIndex(firstVisibleItemIndex);

Наконец, если это сделано по той же причине, по которой мы могли бы кэшировать результат длительного метода, то как мы должны знать, к каким свойствам нужно обращаться таким образом?

Ответы [ 3 ]

0 голосов
/ 04 мая 2018

Почему вместо этого?:

GeneratorPosition position =
 this.ItemContainerGenerator.GeneratorPositionFromIndex(firstVisibleItemIndex);

Давайте рассмотрим это более абстрактно:

  1. У нас есть генератор. На данный момент это this.ItemContainerGenerator, но это может измениться.
  2. Мы используем это. Только один раз здесь, но обычно в нескольких утверждениях.

Когда мы позже решим получить этот генератор в другом месте, использование должно остаться прежним.

Пример слишком мал, чтобы сделать это убедительным, но здесь есть какая-то логика, которую следует различить.

0 голосов
/ 04 мая 2018

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

  • отладка некоторого фрагмента кода, и вам нужно мгновенно увидеть значение переменной
  • делает несколько операций за один раз с объектом, который требует приведения - в результате вы разыгрываете его один раз
  • и иногда, когда вы используете объекты типа значения, этот тип создания локальной копии дает вам возможность не изменять значение свойства class
0 голосов
/ 04 мая 2018

Во-первых, он избегает звонить .InternalChildren много раз. Это может быть небольшим, но заметным сокращением виртуальных вызовов (поскольку оно используется в цикле), но в некоторых случаях оно может быть гораздо более значительным. В некоторых случаях свойство, которое возвращает коллекцию или массив, может выделять каждый раз, когда оно вызывается ; DataRow.ItemArray является классическим примером этого - так что активно вредно вызывать его каждый раз. Дополнительное соображение заключается в том, что даже если он возвращает один и тот же массив каждый раз, когда он вызывается, существует волшебство JIT, которое происходит при проверке границ elide, но это будет работать только в том случае, если JIT увидит, что вы перебираете один массив для всего продолжительность. Если вы вставите средство доступа к свойству посередине: это не будет очевидно, и удаление проверки границ не произойдет. Этого также может не произойти, если вы вручную подняли верхнюю границу!

Примечание: если это не массив, то foreach, вероятно, обычно будет предпочтительнее, и не будет каким-либо преимуществом для введение локально, из-за того, как foreach работает внутри.


Примечание: поскольку вы используете .Count против .Length, это определенно не массив, и вам, вероятно, следует упростить до:

foreach(UIElement child = in arrangeElement.InternalChildren) {...}

или

foreach(var child = in arrangeElement.InternalChildren) {...}

Это не только полностью удаляет этот вопрос, но и означает, что собственный итератор типа (который может быть оптимизированным структурным итератором или простым IEnumerable<T> классом, таким как сгенерированный компилятором блок итератора) может быть используемый. Обычно он имеет более прямой доступ к внутренним компонентам и, таким образом, обходит несколько косвенных проверок и проверок API, которые требуются индексаторам.

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