静态构造函数在同一个appdomain中被调用两次?

buc*_*ley 5 .net c# log4net fody-costura

这个问题更多的是关于C#而不是关于log4net(我认为).

我创建了一个自定义appender,让它读取程序先前设置的静态字段.

令我惊讶的是,静态字段被重新初始化,并且设定值不会使其成为追加者.

我启动了debugview,发现静态构造函数被调用了两次(!).这应该在同一个appdomain中不可能吗?只有debugview才能解决这个问题,因为VS没有在断点上第二次命中.

请注意,这不是关于避免使用log4net的静态变量的问题.我对log4net使用什么样的魔法来实现这个目标感兴趣?

编辑#1

你好约翰,大粉丝.

我按照要求进一步隔离了它.首先,我开始空白并努力解决暴露错误的目标情况.由于我几乎匹配了目标角色,但仍然没有重复,我反过来了.

从错误情况开始,我删除了所有我认为不重要的东西,直到它开始......按预期工作.

当运行时试图解析log4net程序集时,似乎有一些奇怪的事情(如在调试模式中观察到的那样)

这是我在debugview中看到的:

[7756]一般:WARN - 无法解析模块的'log4net'版本.异常:System.NullReferenceException:未将对象引用设置为对象的实例.[7756]在DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor(String modulePath,String moduleLoadMessage,Boolean isUserCode,String name,String version)[7756]一般:WARN - 无法解析模块的"FollowUp.Common"版本.异常:System.NullReferenceException:未将对象引用设置为对象的实例.[7756]在DebuggerShared.Services.EventArgs.ModuleLoadedInDebuggerEventArgs..ctor(String modulePath,String moduleLoadMessage,Boolean isUserCode,String name,String version)

并且VS在调试模块屏幕中没有显示路径的值.现在我是如何设法达到这种状况的?很奇怪,它设法加载程序集,但不能告诉从哪里:)

这是一个孤立的情况,如果我进一步修改它开始按预期工作.

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

我仍然对技术细节感兴趣,但在删除对log4net的引用并再次添加它之后,它们都开始重新运行了.我很高兴它有效,但它让我觉得我没有彻底的解释

此外,静态构造函数*现在被调用两次,这是有意义的,因为当log4net得到它时,类型再次初始化.

我认为花费更多时间在这个原因上是不值得的,我认为解决方案处于一种奇怪的状态并且理解所有这些都具有边际价值.不过,如果你能想到解释这个的话,我会很高兴来到这里.

编辑#2

事实证明,有些程序集确实被加载了两次,包括一个带有静态构造函数的程序集.我稍后会调查这是如何实现的,但我通过禁用和启用Costura来解决这个问题.Costura是一个msbuild任务,它将所有程序集合并为一个.我不是说Costura是根本原因.可能很容易就是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最虚拟地址空间的两倍

编辑#3 Costura使装配加载两次.项目所有者在同一天修复了该问题:) http://code.google.com/p/costura/issues/detail?id=17&thanks=17&ts=1328826304

我们需要一个Costura标签,但我没有必要的1500点声望点.如果您拥有这些权利,请创建它.谢谢.

亲切的问候,汤姆

Cod*_*aos 5

看起来您设法将两个单独的实例加载log4net到同一个AppDomain.

一项目参考:

<Reference Include="log4net">
  <HintPath>..\packages\log4net.1.2.11\lib\net35-full\log4net.dll</HintPath>
</Reference>
Run Code Online (Sandbox Code Playgroud)

另一个:

<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>..\ExternalReferences\log4net.dll</HintPath>
</Reference>
Run Code Online (Sandbox Code Playgroud)

其中一个是强命名的,另一个不是,这导致 .net 给了他们不同的身份。并且提示路径也不同。另外一个似乎是1.2.10,另一个1.2.11

尝试调用AppDomain.GetAssemblies()并检查是否log4net发生两次。

  • 如果程序集的两个实例被加载,那么它们中的每一个都会得到一个完全独立的类,这些类恰好具有相同的名称。因此,每个静态构造函数都会被调用一次。如果你检查他们的`AssemblyQualifiedName`,它可能会有所不同。 (3认同)