TypeLoadException скрывает внутреннее исключение - PullRequest
2 голосов
/ 05 октября 2010

Я использую Compact Framework 3.5 / VS2008. Я получаю очень странное поведение с TypeLoadException. Следующий код выдает эту ошибку. Причина - проблема с подключением к базе данных. Однако по какой-то неизвестной причине это внутреннее исключение потеряно и не содержится в исключении TypeLoadException.

try
{
    settingsFromDb = SettingsFromDbManager.Instance;
}
catch (Exception ex)
{
    throw ex; // BREAKPOINT HERE
}

Если мы посмотрим на класс SettingsFromDbManager ниже, то увидим, что это простой одноэлементный класс. Ошибка базы данных происходит в методе Load (). Я не включил этот код в пример. Если я поставлю точку останова в позиции, указанной в примере ниже, я могу увидеть ошибку базы данных. К сожалению, если я поставлю точку останова в позиции, указанной в коде выше, тогда все, что я получу, это исключение TypeLoadException без внутреннего исключения. Нет ничего, что указывало бы на проблему с базой данных. Это плохо :( Кто-нибудь знает, почему это странное поведение может происходить ??

Приветствия
Mark

public sealed class SettingsFromDbManager
{
    static readonly SettingsFromDbManager _instance = new SettingsFromDbManager(); 

    SettingsFromDbManager()
    {
        try
        {
            Load();
        }
        catch (Exception ex)
        {
            throw ex; // BREAKPOINT HERE
        }
    }

    public static SettingsFromDbManager Instance
    {
        get
        {
            return _instance;
        }
    }

    .... more code ...
}

** Обновление **

Большое спасибо за все замечательные предложения и помощь!

Пьер Я использовал тестовый класс, который вы так любезно написали. Вот код, с которым я его назвал. Я предполагаю, что это должно быть причудой Compact Framework, потому что когда я изучал исключение, это было исключение TypeLoadException без внутреннего исключения: (

try
{
    Fail.Test();
}
catch (Exception ex)
{
    var x = ex.ToString(); // BREAKPOINT HERE
}

Я думаю, что VinayC, вероятно, прав насчет причины. Это все немного за пределами моих знаний. Не уверен, что делать сейчас. Я не хочу отказываться от своих синглтон-классов - они полезны. Я использую «четвертую версию» шаблона Singleton из http://csharpindepth.com/Articles/General/Singleton.aspx.. Я не использовал их раньше, но мне показалось хорошей идеей поделиться одним и тем же экземпляром некоторых служебных классов вокруг приложения, а не создавать и утилизировать их многочисленные раз. Производительность - большая проблема с Compact Framework.

* Обновление *

WOO HOO! Все, что мне нужно было сделать, это изменить класс Singleton следующим образом. Он создает экземпляр класса в свойстве getter. Теперь мои исключения всплывают на поверхность, как и ожидалось:)

public sealed class SettingsFromDbManager
{
    static SettingsFromDbManager _instance = null; 

    SettingsFromDbManager()
    {
        try
        {
            Load();
        }
        catch (Exception ex)
        {
            throw new Exception("Error loading settings", ex); 
        }
    }

    public static SettingsFromDbManager Instance
    {
        get
        {
            if (_instance == null)
                _instance = new SettingsFromDbManager();

            return _instance;
        }
    }

    .... more code ...
}

Ответы [ 2 ]

2 голосов
/ 05 октября 2010

Из того, что я знаю, статические конструкторы могут работать в другом потоке (или, более конкретно, в другой цепочке вызовов) - это гарантия времени выполнения, что они будут вызваны до обращения к типу. Исключение в статическом конструкторе помечает тип как недоступный для домена приложения. При обращении к типу вы получите исключение TypeInitializationException (согласно документации), но возникшее исключение внутри конструктора типа не будет являться внутренним исключением, поскольку оно не находится в той же цепочке вызовов - в этом отношении статический конструктор мог выполняться раньше. Единственной загадкой здесь является TypeLoadException вместо TypeIntializationException, как указал Ганс.

Редактировать: Вот статья , в которой объясняется ленивая / энергичная семантика инициализаторов типов. Ваш код может быть готов к реализации (то есть статический конструктор может быть вызван даже до первого доступа к полю типа)

1 голос
/ 05 октября 2010

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

Вот пример кода, который выдает System.TypeInitializationException с внутренним исключением, установленным в исключение "failed":

class Fail
{
    static Fail()
    {
    }

    Fail()
    {
        throw new System.Exception ("failed");
    }

    static readonly Fail instance = new Fail ();

    public static void Test()
    {
    }
}

Я бы продолжил изучение, чтобы понять, почему вместо этого вы получаете TypeLoadException, что должно происходить, когда сборка не может быть должным образом загружена или инициализирована ( Класс TypeLoadException в MSDN).

...