代码之家  ›  专栏  ›  技术社区  ›  testalino

ApplicationSettingsBase中的FileNotFoundException

  •  29
  • testalino  · 技术社区  · 14 年前

    调试应用程序时,如果在Visual Studio中启用了Break-on异常,则始终会出现以下错误。这真的让我恼火,因为我们工作时有例外。有趣的是,当我继续(加载StringCollection)时,它仍然有效。

    信息是:

    无法加载文件或程序集“system.xmlserializers,version=4.0.0.0,culture=neutral,publickeytoken=b7a5c561934e089”或其依赖项之一。系统找不到指定的文件。

    下面是导致异常的代码(由设计器生成)

    [global::System.Configuration.UserScopedSettingAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    public global::System.Collections.Specialized.StringCollection Mru {
            get {
                return ((global::System.Collections.Specialized.StringCollection)(this["Mru"]));
            }
            set {
                this["Mru"] = value;
            }
        }
    

    我试图创建一个显示错误的空测试应用程序,但没有发生异常。我们的项目很大,所以很难找到原因。也许这个网站上有人知道如何解决这个问题。

    3 回复  |  直到 14 年前
        1
  •  54
  •   Hans Passant    14 年前

    只是解释为什么抛出这个异常。您可以使用此示例Windows窗体应用程序重新设置异常。首先添加一个名为“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);
        }
    }
    

    调试+异常,勾选clr异常的抛出复选框。运行表单并关闭它,当抛出异常时,调试器将停止。调用堆栈的顶部如下所示:

    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);      // <=== here
        }
        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框架中的类,它生成的程序集名称无效。框架中实际上没有“system.xmlserializers.dll”程序集。

    在connect.microsoft.com上关于此行为的反馈报告都已用“按设计”关闭。原来,最初的设计者认为防止异常的成本太高,所以决定只捕获异常。这一切都很好,但这个例外确实被抓住了。您只是碰巧看到它,因为您在“调试+异常”对话框中打开了“引发”复选框。

    在这里,使XML序列化代码的行为不同不是一个选项。对于他们来说,简单地过滤掉system.dll程序集中的类型就足够容易了,但是这是一场可能永远不会结束的战斗,框架中还有很多程序集。解决方法是使用您自己的类来存储设置,而不是使用StringCollection。

        2
  •  6
  •   Community omersem    7 年前

    因为这似乎是正常操作的一部分(另见: XmlSerializer giving FileNotFoundException at constructor )我只能提供两种解决方法:

    禁用此特定异常:Goto调试/异常,单击Add,Type:C++异常,名称:EEFLIORADEXCEPTION(如果这是您所看到的异常),请取消该异常的抛出复选框。

    将设置类型更改为string并访问它,例如:

    var mru = Settings.Default.Mru.Split('|');
    Settings.Default.Mru = string.Join("|", mru.ToArray());
    
        3
  •  1
  •   Coding Flow    14 年前

    您捕获的异常太多,System.XmlSerializer将始终将此异常作为其正常操作的一部分抛出,并由类本身捕获和处理。更改调试选项以仅捕获异常,而不是在.NET FarmeWork类中捕获和处理的异常。

    推荐文章