2010-08-26 5 views
6

Этот вид эзотерический. Я побежал в NullReferenceException при попытке открыть форму (в конструкторе WinForms) в проекте WinForms в Visual Studio 2008. трассировки стека указывает на четвертой строке следующего кода:Почему '{' выбрасывает исключение NullReferenceException в статическом методе?

public static class Logger 
{ 
    public static void LogMethodEnter() 
    { 
     var frame = new StackFrame(1); 
     var method = frame.GetMethod(); 
     Trace.TraceInformation("{0}.{1}.{2}()", method.DeclaringType.Namespace, method.DeclaringType.Name, method.Name); 
     Trace.Indent(); 
    } 

    public static void LogMethodExit() 
    { 
     Trace.Unindent(); 
    } 
} 

... смысл линия с открывающей фигурной скобкой. Я столкнулся с той же проблемой (но не с участием дизайнера winforms) в других проектах, и я думаю, что это была проблема, связанная с потоками, но у меня нет кода для ее репликации.

Почему это происходит и почему трассировка стека исключений указывает на линию с фигурной скобкой?

Уточнение: Исключительное исключение с ссылкой только в дизайнере winforms. Когда приложение запускается, оно не вызывает эту ошибку.

+1

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

+2

Вы пробовали очистить раствор и перестроить? – FrustratedWithFormsDesigner

+1

@Rup: Согласитесь с кодом, который VS жалуется на не синхронизацию с файлом - возможно, он работает с чем-то, что кэшируется? – FrustratedWithFormsDesigner

ответ

4

Я предполагаю, что номера строк выключены (фактическая причина, что это не так важно) и исключение фактически выброшены этим выражением:

method.DeclaringType.Namespace 

И причины вы можете увидеть NullReference Исключение есть потому, что выражение new StackFrame(1) пару предыдущих строк может иногда возвращать пустой кадр. Пустой кадр означает, что вызов .GetMethod() вернет null, и там вы идете.

Причина, по которой вы иногда получаете пустой фрейм, заключается в том, что компилятор «точно в срок» может выбирать встроенные короткие, многократно вызываемые методы, такие как один в вашем коде. Это сбросит ваш стек вызовов, поэтому в лучшем случае вы получите метод более высокого уровня, чем вы планировали, или в худшем случае (в вашем основном методе) нет более высокого метода, и вы получите нуль.

+0

Интересно. Так не означает ли это, что приложение выдает это исключение во время выполнения? Я не видел этого поведения, я полагаю, я должен уточнить, что исключение ТОЛЬКО возникает, когда я пытаюсь открыть форму в дизайнере winforms. –

+0

@Zach Я думаю, что исключение возможно во время выполнения, но вы, вероятно, никогда не увидите его в winforms, потому что вряд ли вы будете использовать вызов этого метода Main в верхней части стека. Вместо этого вы можете увидеть некоторые неправильные записи журнала в тех местах, где это встроено. Вы видите это в дизайнере, потому что визуальная студия показывает, как визуальная студия запускает код, чтобы выяснить поведение/внешний вид дизайнера. Вдруг в верхней части стека работает встроенный вызов. –

+1

Спасибо за понимание, я не знал о inlining - я попробую атрибут [MethodImpl] и некоторую нулевую проверку. –

0

Указывая на фигурный скобок /, казалось бы, некорректная строка кода может когда-нибудь произойти. Я думаю, что просто исключение произошло в предыдущей строке кода, а Visual Studio почему-то выделяет следующую строку.

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

Извините, я не могу объяснить это очень хорошо.

+0

Visual Studio Выделите следующую строку, когда выполнение прошло предыдущей строки, но еще не достигло следующей строки. Вы увидите это в большинстве случаев, когда Visual Studio выделяет линию зеленым цветом; что ошибка произошла внутри метода, вызванного предыдущей строкой. –

1

Я думаю, что проблема связана со статическим методом, вызываемым перед построением статического объекта. Я исправил проблему в проекте winforms, добавив static constructor.

Если я правильно помню, статический конструктор блокирует весь объект во время выполнения.

+0

Получает ли ваш метод доступ к любым статическим полям класса? –

+0

Нет, единственное, что использует метод, это StackFrame и объект Trace, ни один из которых не является статическими полями класса. –

+0

И что-нибудь еще в вашем классе? Мне просто интересно, почему статический конструктор решил проблему. Это кажется возможным, потому что добавление статического конструктора изменяет поведение инициализации статического класса. –

3

Это может быть, что файл .pdb, содержащий информацию о линии устарело.

Чтобы исправить это, перестройте проект и убедитесь, что в файлах проекта включено создание файлов .pdb. Для C# проектов это может быть настроен на вкладке сборки путем установки Дополнительно -> Debug Info либо полный или PDB только.

+0

Хорошее предложение, я столкнулся с этим прежде. Но я уже пробовал это, никакого эффекта. –

4

Я предполагаю, что у вас есть инициализация статического члена где-то в вашем классе, и этот инициализатор выдает NullReferenceException. Кроме того, я полагаю, у вас нет статического конструктора, поэтому ваш объект помечен как beforefieldinit, и поэтому вызывается NullReferenceException, в то время как ваш метод, который его использует, JITed.

Что-то вроде:

public static class Logger 
{ 
    private static object x = InitObjectX(); 
    private static object InitObjectX() { 
     x.GetHashCode(); // Will throw since x is null. 
    } 

    public static void LogMethodEnter() 
    { 
     var frame = new StackFrame(1); 
     var method = frame.GetMethod(); 
     Trace.TraceInformation("{0}.{1}.{2}()", method.DeclaringType.Namespace, method.DeclaringType.Name, method.Name); 
     Trace.Indent(); 
    } 

    public static void LogMethodExit() 
    { 
     Trace.Unindent(); 
    } 
} 
+1

Мне нравится это предположение. –

+0

Хм, есть несколько статических полей, но они инициализируются так: static string Name = "xyz"; Это вызовет ту же проблему? –

+1

Я думал то же самое, но исключение во время инициализации статического класса обычно приводит к 'TypeInitializationException' (с NRE как внутренним исключением). –

Смежные вопросы