Статический конструктор вызывается дважды в одном домене приложения? - PullRequest
5 голосов
/ 08 февраля 2012

Этот вопрос больше о C #, чем о log4net (я думаю).

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

К моему удивлению, статическое поле было повторно инициализировано, и заданное значение не дошло до аппендера.

Я запустил debugview и увидел, что статический конструктор вызывается дважды (!).Это не должно быть возможно в том же домене приложения, верно?Только debugview выявил это, поскольку VS не ударял второй раз по точке останова.

Обратите внимание, что речь не идет об избежании использования статической переменной с log4net.Мне интересно, какую магию использует log4net для достижения этой цели?

Edit # 1

Привет, Джон, Большой поклонник.

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

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

Кажется, что есть какая-то странная вещь, зависшая, когда среда выполнения пытается разрешить сборку log4net (как это наблюдается в режиме отладки)

Это то, что я вижу с debugview:

[7756] Общее: WARN - Не удалось проанализировать версию модуля 'log4net'.Исключение: System.NullReferenceException: ссылка на объект не установлена ​​для экземпляра объекта.[7756] at DebuggerShared.Services.EventArgs.Исключение: System.NullReferenceException: ссылка на объект не установлена ​​для экземпляра объекта.[7756] at DebuggerShared.Services.EventArgs.,Теперь, как мне удалось прийти к этой ситуации?Странно, что ему удалось загрузить сборку, но я больше не могу сказать откуда:)

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

https://www.sugarsync.com/pf/D6486369_1701716_00940

Меня все еще интересуют технические детали, но после удаления ссылки на log4net и добавления ее снова все снова заработало.Я счастлив, что это работает, но меня беспокоит то, что у меня нет подробного объяснения

Кроме того, статический конструктор * теперь вызывается дважды *, что имеет смысл, поскольку тип снова инициализируется, когда log4net получает егоруки на это.

Я думаю, что не стоит тратить больше времени на это, потому что я думаю, что решение было в странном состоянии и понять, что все это имеет предельную ценность.Тем не менее, если вы можете придумать что-то, чтобы объяснить это, я был бы рад здесь.

Edit # 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-into-the-virtual-address-space-twice

Редактирование # 3 Costura заставил сборки загружаться дважды.Проблема была исправлена ​​в тот же день владельцем проекта :) http://code.google.com/p/costura/issues/detail?id=17&thanks=17&ts=1328826304

Нам нужен тег Костура, но у меня нет необходимых 1500 очков репутации. Пожалуйста, создайте его, если у вас есть права. Спасибо.

С уважением, Том

Ответы [ 2 ]

4 голосов
/ 08 февраля 2012

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

1 голос
/ 08 февраля 2012

Ну, это может быть явно вызванным инициализатором типа:

var initializer = typeof(Foo).TypeInitializer;
initializer.Invoke(null);

Однако я бы надеялся , что он этого не делает.Можете ли вы придумать короткую, но полную программу, которая демонстрирует это?

...