Использование статических локальных переменных в свойстве отложенной загрузки в VB.NET - PullRequest
5 голосов
/ 19 сентября 2011

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

Рассмотрим следующий пример кода.

Public Class Foo
  Implements IFoo
End Class

Public Interface IFoo
End Interface

Public Class Bar

  Private _fooImplementation As IFoo
  Public ReadOnly Property FooImplementation As IFoo
    Get
      If _fooImplementation Is Nothing Then _fooImplementation = New Foo
      Return _fooImplementation
    End Get
  End Property
End Class

Это обычное упрощенное свойство отложенной загрузки. Возможно, вы даже захотите использовать универсальный класс Lazy для получения (насколько мне известно) того же поведения.

Теперь давайте посмотрим на свойство при использовании статической переменной.

Public Class Bar

  Public ReadOnly Property FooImplementation As IFoo
    Get
      Static _fooImplementation as IFoo = New Foo
      Return _fooImplementation
    End Get
  End Property
End Class

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

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

Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 19 сентября 2011

Ключевое слово Static имеет много накладных расходов, компилятор генерирует большой кусок IL для его реализации. То, что делает , что ваш 1-й фрагмент не делает, - это гарантирует, что многопоточность не вызывает проблем. Если это не проблема, то ваш 1-й фрагмент на лот дешевле. Не только потому, что у него намного меньше IL, но и потому, что он будет встроенным. Метод получения со Static никогда не будет встроен, поскольку он содержит код Try / finally.

Если вы ориентируетесь на .NET 4, вам определенно стоит взглянуть на класс Lazy (Of T).

1 голос
/ 19 сентября 2011

Этот вопрос был достаточно интересным для меня, чтобы найти ответ ... как именно VB.NET реализует статическое. Вот эквивалент C #:

public class Bar
  {
    [SpecialName]
    private IFoo \u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation;
    [SpecialName]
    private StaticLocalInitFlag \u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init;

    public IFoo FooImplementation
    {
      get
      {
        Monitor.Enter((object) this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init);
        try
        {
          if ((int) this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init.State == 0)
          {
            this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init.State = (short) 2;
            this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation = (IFoo) new Foo();
          }
          else if ((int) this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init.State == 2)
            throw new IncompleteInitialization();
        }
        finally
        {
          this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init.State = (short) 1;
          Monitor.Exit((object) this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init);
        }
        return this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation;
      }
    }

    [DebuggerNonUserCode]
    public Bar()
    {
      this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init = new StaticLocalInitFlag();
    }
  }
...