C#: использование блока: объектная реинициализация

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

Почему "использование" вызова располагает на исходном значении а не на последней ссылке или реинициализации (который происходит, если попытка наконец блок используется),

MyClass b = new MyClass();// implements Idisposable
MyClass c = new MyClass();
MyClass a ; 

 using (a = new MyClass())
 {
                a = b;
                a = c;
 }

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

Однако с попыткой {} наконец кодируют последнюю ссылку, располагают метод, назван.

try
{
   a = new MyClass();
   a = b;
   a = c;
 }
  finally 
   {
   a.Dispose();
  }

MSDN: оператор использования гарантирует, чтобы Расположили, назван, даже если исключение происходит, в то время как Вы - вызывающие методы для объекта.

using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

В основном "использование" переводит в:

{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

5
задан TheSoftwareJedi 22 February 2010 в 12:55
поделиться

6 ответов

Компилятор генерирует следующий код:

MyClass b = new MyClass();
MyClass a;
MyClass cs$3$000 = a = new MyClass();
try {
  a = b;
}
finally {
  if (cs$3$000 != null) cs$3$000.Dispose();
}

Автоматически сгенерированная локальная переменная cs $ 3 $ 000 реализует контракт.

3
ответ дан 18 December 2019 в 10:44
поделиться

Есть две формы с использованием операторов , определенных в спецификации C #:

using-statement:
    using   (    resource-acquisition   )    embedded-statement
resource-acquisition:
    local-variable-declaration
    expression

Если у вас есть объявление-локальной-переменной , вопросов не возникнет. Переменная будет доступна только для чтения в блоке using, и вы вообще не сможете ее изменить. В спецификации говорится:

8.13 Оператор using

[...] В любом раскрытии переменная ресурса доступна только для чтения в встроенный оператор.

Здесь мы имеем дело со второй формой: где получение ресурса - это выражение , а не объявление локальной переменной . В этом случае спецификация C # ясно говорит:

Оператор using формы

  оператор using (выражение) 
 

имеет те же два возможных расширения, но в этом случае ResourceType неявно является тип выражения во время компиляции, и переменная ресурса недоступна и невидима для встроенного оператора . [курсив мой]

Очевидно, вы не можете изменить невидимую, недоступную переменную. Его значение присваивается только в предложении using resource-capture . Следовательно, у него будет старое значение переменной, а не новое.

Когда вы имеете дело с присваиванием уже объявленной переменной , вы используете эту форму оператора using . Тот факт, что вы присваиваете значение переменной , например

using ( x = something )

, не имеет значения. Целое x = something рассматривается как выражение, и только значение этого выражения имеет значение.Важно знать, что «переменная ресурса» здесь не «x». Это невидимая переменная. С точки зрения компилятора, нет большой разницы между следующими конструкциями:

using ( something ) 
using ( x = something )
using ( y = x = something )

Во всех случаях будет выполняться выражение и значение - это то, что получит гарантированное удаление, а не переменная. Что должен был бы сделать компилятор, если бы это не было определенным поведением и вы написали третью строку в приведенном выше блоке? Утилизировать x ? и ? оба? ни один? Текущее поведение имеет смысл.

8
ответ дан 18 December 2019 в 10:44
поделиться

Using можно рассматривать как обещание вызвать disposed на объекте, объявленном с помощью using. Это единственное, что, ИМХО, имеет смысл!

Если вы вызовете dispose на переназначенном значении, то исходное значение не будет утилизировано.

3
ответ дан 18 December 2019 в 10:44
поделиться

Dispose будет вызван на объекте, на который ссылается аргумент в выражении using. Все просто.

0
ответ дан 18 December 2019 в 10:44
поделиться

Похоже, что "using" создает свою собственную переменную для хранения ссылки, которая инициализируется на "a", который в свою очередь инициализируется на первый экземпляр объекта. Позже, когда вы изменяете "a", вы на самом деле не изменяете исходную ссылку, которая была сохранена в операторе "using". Это кажется довольно хорошей функцией, поскольку using отвечает за утилизацию фактического объекта, упомянутого в операторе using, а не переменной.

1
ответ дан 18 December 2019 в 10:44
поделиться

Да, это интересно.

Итак, я посмотрел на декомпилированный код:

  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication17.Foo1::.ctor()
  IL_0006:  dup
  IL_0007:  stloc.0
  IL_0008:  stloc.1 // 1. note this
  .try
  {
    IL_0009:  nop
    IL_000a:  newobj     instance void ConsoleApplication17.Foo2::.ctor()
    IL_000f:  stloc.0 // 2. and this
    IL_0010:  nop
    IL_0011:  leave.s    IL_0023
  }  // end .try
  finally
  {
    IL_0013:  ldloc.1 // 3. and this
    IL_0014:  ldnull
    IL_0015:  ceq
    IL_0017:  stloc.2
    IL_0018:  ldloc.2
    IL_0019:  brtrue.s   IL_0022
    IL_001b:  ldloc.1
    IL_001c:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0021:  nop
    IL_0022:  endfinally
  }  // end handler
  IL_0023:  nop

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

Действительно, было бы неплохо, если бы в операторе using можно было использовать только переменные "только для чтения". Это немного сбивает с толку. И, конечно, MSDN вводит в заблуждение.

1
ответ дан 18 December 2019 в 10:44
поделиться
Другие вопросы по тегам:

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