Статический конструктор вызывается дважды в одном домене приложения?
Этот вопрос больше о C#, чем о log4net (я думаю).
Я создал собственный appender и позволил ему читать статическое поле, которое было предварительно установлено программой.
К моему удивлению, статическое поле было повторно инициализировано, и заданное значение не дошло до аппендера.
Я запустил debugview и увидел, что статический конструктор вызывается дважды (!). Это не должно быть возможно в том же домене приложения, верно? Только debugview выявил это, так как VS не достиг второй точки останова.
Обратите внимание, что речь не идет об избежании использования статической переменной с log4net. Я заинтересован в том, какую магию log4net использует для достижения этой цели?
Правка № 1
Привет Джон, Большой поклонник.
Я изолировал его дальше, как и просил. Сначала я начал с нуля и работал над целевой ситуацией, которая выявляет ошибку. Так как я почти соответствовал целевому персонажу за персонажем и все еще не воспроизводил, я пошел другим путем.
Исходя из ситуации с ошибкой, я вычеркнул все, что мне показалось несущественным, пока он не начал... работать как положено.
Кажется, есть какая-то странная вещь, которая зависает, когда среда выполнения пытается разрешить сборку log4net (как это наблюдается в режиме отладки)
Вот что я вижу в debugview:
[7756] Общее: WARN - Не удалось проанализировать версию модуля 'log4net'. Исключение: System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта. [7756] at DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor(String modulePath, String moduleLoadMessage, Boolean isUserCode, String name, String version) [7756] Общие сведения: WARN - Не удалось проанализировать версию FollowUmon модуля. Исключение: System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта. [7756] at DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor (String modulePath, String moduleLoadMessage, логический isUserCode, строковое имя, строковая версия)
И VS не показывает значение для пути на экране модуля отладки. Теперь, как мне удалось прийти к этой ситуации? Странно, что ему удалось загрузить сборку, но я не могу больше сказать, откуда:)
Вот такая ситуация, что если я продолжу ее модифицировать, она начнет работать как положено.
https://www.sugarsync.com/pf/D6486369_1701716_00940
Я все еще заинтересован в технических деталях, но после удаления ссылки на log4net и добавления ее снова все снова заработало. Я счастлив, что это работает, но меня беспокоит, что у меня нет подробного объяснения
Кроме того, статический конструктор * теперь вызывается дважды *, что имеет смысл, поскольку тип снова инициализируется, когда ему достается log4net.
Я думаю, что не стоит тратить больше времени на это, я думаю, что решение было в странном состоянии, и понять, что все это имеет предельную ценность. Тем не менее, если вы можете придумать что-то, чтобы объяснить это, я был бы рад здесь.
Редактировать № 2
Оказалось, что некоторые сборки действительно загружались дважды, в том числе со статическим конструктором. Позже я расскажу, как это возможно, но у меня есть обходной путь, отключив и включив Costura. Costura - это задача msbuild, которая объединяет все сборки в одну. Я не говорю, что Костура является основной причиной. Вполне возможно, что файлы csproj/sln находились в странном состоянии.
Размышляя о том, как быстрее диагностировать эту проблему в будущем, я запустил sysinternals ProcessExplorer. Теперь я ожидал, что сборки будут загружаться только один раз, но обнаружил, что они были загружены дважды. Кажется, это ошибка во время выполнения, исправленная только в.NET 4
http://forum.sysinternals.com/why-some-net-assemblies-are-duplicated-in-memory_topic15279.html https://connect.microsoft.com/VisualStudio/feedback/details/467560/clr-maps-assemblies -в-на-виртуального-адрес-пространственно-два раза
Правка № 3 Костура заставил сборки загружаться дважды. Проблема была устранена в тот же день владельцем проекта:) http://code.google.com/p/costura/issues/detail?id=17&thanks=17&ts=1328826304
Нам нужен тег Костура, но у меня нет необходимых 1500 очков репутации. Пожалуйста, создайте его, если у вас есть права. Благодарю.
С наилучшими пожеланиями, Том
2 ответа
Похоже, вам удалось загрузить два отдельных экземпляра log4net
в то же самое AppDomain
,
Один проект ссылки:
<Reference Include="log4net">
<HintPath>..\packages\log4net.1.2.11\lib\net35-full\log4net.dll</HintPath>
</Reference>
Другой:
<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ExternalReferences\log4net.dll</HintPath>
</Reference>
Один из них строго назван, а другой нет, в результате.net дает им разные имена. И путь подсказки тоже отличается. Также один, кажется, 1.2.10
, другой 1.2.11
,
попробуйте позвонить AppDomain.GetAssemblies()
и проверьте, если log4net
происходит дважды.
Что ж, это может быть прямой вызов инициализатора типа:
var initializer = typeof(Foo).TypeInitializer;
initializer.Invoke(null);
Тем не менее, я надеюсь, что это не так. Можете ли вы придумать короткую, но полную программу, которая демонстрирует это?