这个异常被抛出的原因是什么,这里给出一个解释。您可以使用这个简单的Windows Forms应用程序来重现此异常。首先添加一个名为“Setting”的StringCollection类型的设置。点击“值”列中的点并输入一些字符串。让窗体类代码看起来像这样:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
Properties.Settings.Default.Setting[0] = DateTime.Now.ToString();
Properties.Settings.Default.Save();
base.OnFormClosing(e);
}
}
在Debug + Exceptions中,勾选CLR exceptions的Thrown复选框。运行表单并关闭它,当异常被抛出时,调试器将停止。调用栈顶部如下所示:
mscorlib.dll!System.Reflection.Assembly.nLoad(System.Reflection.AssemblyName fileName, string codeBase, System.Security.Policy.Evidence assemblySecurity, System.Reflection.Assembly locationHint, ref System.Threading.StackCrawlMark stackMark, bool throwOnFileNotFound, bool forIntrospection) + 0x2c bytes
mscorlib.dll!System.Reflection.Assembly.InternalLoad(System.Reflection.AssemblyName assemblyRef, System.Security.Policy.Evidence assemblySecurity, ref System.Threading.StackCrawlMark stackMark, bool forIntrospection) + 0x80 bytes
mscorlib.dll!System.Reflection.Assembly.Load(System.Reflection.AssemblyName assemblyRef) + 0x1d bytes
System.Xml.dll!System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null, out System.Xml.Serialization.XmlSerializerImplementation contract = null) + 0xcd bytes
System.Xml.dll!System.Xml.Serialization.XmlSerializer.XmlSerializer(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null) + 0x105 bytes
你可以看到XmlSerializer类正在寻找一个包含StringCollection类的XML序列化器的程序集。LoadGeneratedAssembly方法如下所示,已删除了无趣的部分:
internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract)
{
...
AssemblyName parent = GetName(type.Assembly, true);
partialName = Compiler.GetTempAssemblyName(parent, defaultNamespace);
parent.Name = partialName;
parent.CodeBase = null;
parent.CultureInfo = CultureInfo.InvariantCulture;
try
{
serializer = Assembly.Load(parent);
}
catch (Exception exception)
{
...
}
....
}
Compiler.GetTempAssemblyName()是什么意思:
internal static string GetTempAssemblyName(AssemblyName parent, string ns)
{
return (parent.Name + ".XmlSerializers" + (((ns == null) || (ns.Length == 0)) ? "" : ("." + ns.GetHashCode())));
}
在这种情况下,GetTempAssemblyName方法是罪魁祸首。StringCollection类位于System.dll程序集中,该方法生成名称“System.XmlSerializers”。该方法旨在查找自己类的程序集,即由Sgen.exe生成的程序集,例如您的示例程序的WindowsApplication1.XmlSerializers.dll。但是,StringCollection是.NET Framework中的一个类,它生成的程序集名称并不有效。实际上,在框架中不存在“System.XmlSerializers.dll”程序集。
关于此行为的反馈报告都已被关闭,原因是设计人员认为防止异常的成本太高,决定仅捕获异常。这完全可行,异常确实被捕获了。您之所以看到它,是因为您在“调试+异常”对话框中打开了Thrown复选框。
让Xml序列化代码在此处表现不同不是一个选项。他们本可以轻松地过滤掉System.dll程序集中的类型,但那是一个潜在的永无止境的战斗,在框架中有更多的程序集。解决方法是使用您自己的类来存储设置,而不是使用StringCollection。