Col*_*lin 9 .net c# static-constructor appdomain visual-studio-sdk
我在这里有点头疼,我想知道是否有人知道答案.
设置基本上是这样的:
//in Visual Studio plug-in application
SpinUpProgramWithDebuggerAttached();
//in spun up program
void Start()
{
StaticClass.StaticVariable = "I want to use this.";
XmlSerializer.Deserialize(typeof(MyThingie), "xml");
}
class MyThingie : IXmlSerializable
{
ReadXml()
{
//why the heck is this null?!?
var thingIWantToUse = StaticClass.StaticVariable;
}
}
Run Code Online (Sandbox Code Playgroud)
让我脱头发的问题是,在IXmlSerializable.ReadXml()方法中,StaticClass.StaticVariable为null,即使在设置变量后它被称为RIGHT.
值得注意的是,没有命中断点,并且在问题发生的精确位置忽略Debugger.Launch().
神秘的是,我通过提出异常来确定AppDomain.CurrentDomain.FriendlyName属性对于静态变量填充的位置与null相同!
为什么heck是超出范围的静态变量?!?这是怎么回事?!?我如何分享我的变量?
编辑:
我根据响应中的建议添加了一个静态构造函数,并让它执行Debug.WriteLine.我注意到它被调用了两次,即使所有代码似乎都在同一个AppDomain中运行.这是我在输出窗口中看到的内容,我希望这是一个有用的线索:
静态构造函数调用时间:2015-01-26T13:18:03.2852782-07:00
...加载'C:...\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll'...
......加载'Microsoft.GeneratedCode'......
...加载'C:...\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll'....
...加载'C:\ USERS ...\APPDATA\LOCAL\MICROSOFT\VISUALSTUDIO\12.0EXP\EXTENSIONS ... SharePointAdapter.dll'.符号已加载.
...加载'Microsoft.GeneratedCode'.
静态构造函数调用时间:2015-01-26T13:18:03.5196524-07:00
附加细节:
这是实际的代码,因为有几位评论者认为它可能有所帮助:
//this starts a process called "Emulator.exe"
var testDebugInfo = new VsDebugTargetInfo4
{
fSendToOutputWindow = 1,
dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess,
bstrArg = "\"" + paramPath + "\"",
bstrExe = EmulatorPath,
LaunchFlags = grfLaunch | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_WaitForAttachComplete,
dwDebugEngineCount = 0,
guidLaunchDebugEngine = VSConstants.CLSID_ComPlusOnlyDebugEngine,
};
var debugger = Project.GetService(typeof(SVsShellDebugger)) as IVsDebugger4;
var targets = new[] { testDebugInfo };
var processInfos = new[] { new VsDebugTargetProcessInfo() };
debugger.LaunchDebugTargets4(1, targets, processInfos);
//this is in the emulator program that spins up
public partial class App : Application
{
//***NOTE***: static constructors added to static classes.
//Problem still occurs and output is as follows (with some load messages in between):
//
//MefInitializer static constructor called at: 2015-01-26T15:34:19.8696427-07:00
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.0609845-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.3399330-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
protected override void OnStartup(StartupEventArgs e)
{
//...
//initializes a MEF container singleton (stored as static variable)
MefInitilizer.Run();
//here's where it blows up. the important details are that
//FullSelection implements IXmlSerializable, and its implemention
//ends up referencing the MEF container singleton, which ends up
//null, even though it was initialized in the previous line.
//NOTE: the approach works perfectly under a different context
//so the problem is not the code itself, per se, but a problem
//with the code in the environment it's running in.
var systems = XmlSerialization.FromXml<List<FullSelection>>(systemsXml);
}
}
public static class MefInitilizer
{
static MefInitilizer() { Debug.WriteLine("MefInitializer static constructor called at: " + DateTime.Now.ToString("o")); }
public static void Run()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
var container = new CompositionContainer(catalog);
ContainerSingleton.Initialize(container);
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
Debug.WriteLine("ContainerSingleton static constructor called at: " + DateTime.Now.ToString("o") + ". Type: " + typeof(ContainerSingleton).AssemblyQualifiedName);
}
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
}
Run Code Online (Sandbox Code Playgroud)
感谢所有提出建议的人!我从来没有弄清楚到底发生了什么(如果我这样做的话,我会继续调查/发布更新),但我最终确实想出了一个解决方法。
一些人建议将静态类的初始化内部化,但由于实际问题的性质,初始化逻辑必须外部化(我基本上是加载一个 DI/服务位置容器,其组成因环境而异)。
另外,我怀疑它不会有帮助,因为我可以观察到静态构造函数被调用了两次(因此,无论有什么初始化逻辑都只会被调用两次,这并没有直接解决问题)。
然而,这个建议让我走上了正轨。
就我而言,我加载的服务都不需要是有状态的,因此除了性能影响之外,初始化发生两次并不重要。
因此,我只是让静态类检查 MEF 容器是否已加载,如果没有加载,我将读取指定处理初始化的类的配置文件。
通过这样做,我仍然可以根据环境改变 MEF 容器的组成,目前它运行得很好,即使它不是理想的解决方案。
我想在所有提供帮助的人之间分配赏金,但由于这似乎不可能,我可能会奖励 OakNinja,因为他是一位英雄,根据我提供的信息,提出了尽可能多的好主意。假如。再次感谢!