Почему " {"вызывает исключение NullReferenceException в статическом методе?

Это своего рода эзотерика. Я столкнулся с NullReferenceException при попытке открыть форму (в конструкторе winforms) в проекте winforms в visual studio 2008. Трассировка стека указывает на четвертую строку следующего кода:

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. Когда приложение запускается, оно не выдает эту ошибку.

5 ответов


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

method.DeclaringType.Namespace

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

почему вы иногда получаете пустой кадр, что компилятор just-in-time может выбрать встроенные короткие, неоднократно вызываемые методы, такие как в вашем коде. Это сбросит ваш стек вызовов, так что в лучшем случае вы получите метод более высокого уровня, чем вы намеревались, или в худшем случае (в вашем основном методе) нет более высокого метода, и вы получите null.


Я думаю, что у вас есть инициализация статического члена где-то в вашем классе, и что инициализатор бросает!--1-->. Кроме того, я думаю, у вас нет статического конструктора, поэтому ваш объект помечен как 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(); 
    } 
} 

возможно,.файл pdb содержит информацию о строке устарел.

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


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

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


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

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

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