2009-10-29 3 views
18

Как относительный новичок, я стараюсь как можно больше читать о конкретном предмете и тестировать/писать как можно больше кода. Я смотрел один из Jons Brainteasers (вопрос № 2), и мой результат отличался от ответа. Это приводит меня сюда, чтобы спросить, изменилось ли что-то в последних версиях и посмотреть, какие результаты другие получают от этого кода.Использование статического конструктора (Jon Skeet Brainteaser)

Вопрос в том, «Что будет отображаться, почему и насколько вы уверены?»

using System; 

class Foo 
{ 
    static Foo() 
    { 
     Console.WriteLine ("Foo"); 
    } 
} 

class Bar 
{ 
    static int i = Init(); 

    static int Init() 
    { 
     Console.WriteLine("Bar"); 
     return 0; 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     Foo f = new Foo(); 
     Bar b = new Bar(); 
    } 
} 

Что, если угодно, привело бы нас к двум различным ответам?

+1

Вы спрашиваете «если что-то изменилось в последних версиях Visual Studio». То, что вы действительно спрашиваете, было бы, если бы что-то изменилось в новой версии .NET Framework. И, действительно, ничто из того, что майор не изменится с версии на версию, так как это будет серьезное изменение бремени. –

+1

Дублированный. Интересно. –

+3

Ну, что ответ вы получаете? –

ответ

24

Теперь попробуйте в режиме выпуска вне отладчика ;-p

я получаю разные результаты с/без отладчика. Отладчик расстраивает множество тонких нюансов/оптимизаций, поэтому я могу только догадываться, что это один из тех случаев, когда вопрос отладчика имеет значение. Это затрудняет отладку; -p

+1

Это именно то, чего мне не хватало. –

+1

Я получаю «Foo» в режиме деблокирования «Foo'and'Bar» в режиме отладки. С точки зрения исходного языка программирования, не следует ли последовательно отображать «Foo» и «Bar»? –

6

Личная информация о пользователе answers page. Я не парень C#, но похоже, что у системы есть только один выбор, когда нужно вызвать статический код foo (и, следовательно, написать «Foo»), но у него есть практически бесконечная свобода решать, когда инициализировать Bar.i (что будет писать «Bar»), так что это может произойти либо при загрузке класса, либо при его первом использовании, либо вообще нет.

0

Просто посмотрев на него, я был бы удивлен, если бы он отображал что-то еще, кроме «FooBar».

По простой причине вы сначала получаете доступ к Foo, поэтому его статический конструктор будет работать. За ним следует инициализатор статического поля при создании бара.

Счастливые исправления.

4

Он печатает Foo, Bar в режиме отладки и Bar, Foo в режиме деблокирования. Так что происходит, когда код Release оптимизирован, и оптимизация вызывает вызов Bar сначала - но есть no гарантия, что всегда будет так.

+1

Почему сначала нужно вызвать панель оптимизации. Какое правило здесь? –

+0

Мне нужно было бы проверить, но я не удивлюсь, если это отладчик, больше, чем отладка/выпуск, что-то расстраивает. Это регулярно. –

+2

Поскольку у бара нет статического конструктора, он может инициализировать значение для i и довести класс Bar досрочно. Это предотвратит дальнейшую работу позже. В качестве альтернативы, отладчик позволяет банку активизировать позже.Foo, поскольку он имеет конструктор, всегда будет инициализироваться при первом создании, а Bar может быть инициализирован в любое время. –

0

Я думаю, что панель foo будет напечатана. Конструктор статического типа будет выполнен сначала в Foo, тогда метод Init будет вызываться в классе Bar. Я не знаю, изменилось ли поведение. Это интересно.