Irw*_*win 340 c# xml-serialization
当我尝试序列化类型时,我一直在使用的应用程序失败.
像这样的陈述
XmlSerializer lizer = new XmlSerializer(typeof(MyType));
Run Code Online (Sandbox Code Playgroud)
生产:
System.IO.FileNotFoundException occurred
Message="Could not load file or assembly '[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
Source="mscorlib"
FileName="[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
FusionLog=""
StackTrace:
at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
Run Code Online (Sandbox Code Playgroud)
我没有为我的班级定义任何特殊的序列化器.
我该如何解决这个问题?
Mar*_*urn 375
信不信由你,这是正常行为.抛出异常但由XmlSerializer处理,所以如果你忽略它,一切都应该继续正常.
我发现这很烦人,已经有很多抱怨这一点,如果你周围有点搜索,但是从我读过微软不准备做任何事情的计划.
如果关闭该特定异常的第一次机会异常,则可以避免在调试时始终获取异常弹出窗口.在Visual Studio中,转到Debug - > Exceptions(或按Ctrl+ Alt+ E),Common Language Runtime Exceptions - > System.IO - > System.IO.FileNotFoundException.
您可以在博客文章C#XmlSerializer FileNotFound异常(Chris Sells的工具XmlSerializerPreCompiler)中找到有关其他方法的信息.
All*_*nek 104
就像Martin Sherburn所说,这是正常的行为.XmlSerializer的构造函数首先尝试查找名为[YourAssembly] .XmlSerializers.dll的程序集,该程序集应包含用于序列化类型的生成类.由于尚未生成此类DLL(默认情况下不是这样),因此抛出FileNotFoundException.当发生这种情况时,XmlSerializer的构造函数捕获该异常,并且XmlSerializer的构造函数在运行时自动生成DLL(这是通过在计算机的%temp%目录中生成C#源文件,然后使用C#编译器编译它们来完成的).对于相同类型的XmlSerializer的其他构造将仅使用已经生成的DLL.
更新:从.NET 4.5开始,
XmlSerializer不再执行代码生成,也不使用C#编译器执行编译,以便在运行时创建序列化程序程序集,除非通过设置配置文件设置(useLegacySerializerGeneration)显式强制执行.此更改消除了依赖性csc.exe并提高了启动性能.来源:.NET Framework 4.5自述文件,第1.3.8.1节.
该异常由XmlSerializer的构造函数处理.您无需自己做任何事情,只需单击"继续"(F5)继续执行您的程序,一切都会好的.如果您对停止执行程序并弹出异常帮助程序的异常感到困扰,则可以关闭"Just My Code",或者将FileNotFoundException设置为在抛出时执行,而不是在"User-未处理".
要启用"Just My Code",请转到工具>>选项>>调试>>常规>>启用我的代码.要在抛出FileNotFound时关闭执行中断,请转到Debug >> Exceptions >> Find >> enter'FileNotFoundException'>>取消选中System.IO.FileNotFoundException中的'Thrown'复选框.
Vla*_*adV 63
在Visual Studio项目属性("构建"页面,如果我没记错),有一个选项说"生成序列化程序集".尝试为生成[包含MyType程序集]的项目启用它.
qua*_*ity 58
有一个解决方法.如果你使用
XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];
Run Code Online (Sandbox Code Playgroud)
它应该避免这种例外.这对我有用.
警告: 不要多次使用,否则会有内存泄漏
如果你使用这种方法XmlSerializer多次创建同一类型的实例,你会像疯了一样泄漏内存!
这是因为此方法绕过了提供者XmlSerializer(type)和XmlSerializer(type, defaultNameSpace)构造函数(所有其他构造函数也绕过缓存)的内置缓存.
如果您使用任何方法来创建不通过这两个构造函数的XmlSerializer,您必须实现自己的缓存,否则您将出血.
小智 21
我遇到了这个问题,无法通过提到的任何解决方案解决这个问题.
然后我终于找到了解决方案.似乎序列化程序不仅需要类型,还需要嵌套类型.改变这个:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
Run Code Online (Sandbox Code Playgroud)
对此:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes());
Run Code Online (Sandbox Code Playgroud)
解决了我的问题.没有更多例外或任何事情.
我的解决方案是直接进行反射以创建序列化器.这绕过了导致异常的奇怪文件加载.我将它打包在一个辅助函数中,该函数也负责缓存序列化程序.
private static readonly Dictionary<Type,XmlSerializer> _xmlSerializerCache = new Dictionary<Type, XmlSerializer>();
public static XmlSerializer CreateDefaultXmlSerializer(Type type)
{
XmlSerializer serializer;
if (_xmlSerializerCache.TryGetValue(type, out serializer))
{
return serializer;
}
else
{
var importer = new XmlReflectionImporter();
var mapping = importer.ImportTypeMapping(type, null, null);
serializer = new XmlSerializer(mapping);
return _xmlSerializerCache[type] = serializer;
}
}
Run Code Online (Sandbox Code Playgroud)
要避免异常,您需要做两件事:
将System.Xml.Serialization.XmlSerializerAssembly属性添加到您的类.将'MyAssembly'替换为MyClass所在的程序集的名称.
[Serializable]
[XmlSerializerAssembly("MyAssembly.XmlSerializers")]
public class MyClass
{
…
}
Run Code Online (Sandbox Code Playgroud)
使用sgen.exe实用程序生成序列化文件,并使用类的程序集进行部署.
'sgen.exe MyAssembly.dll'将生成文件MyAssembly.XmlSerializers.dll
这两个更改将导致.net直接查找程序集.我检查了它,它适用于使用Visual Studio 2008的.NET framework 3.5
函数XmlSerializer.FromTypes不会抛出异常,但会泄漏内存.这就是为什么你需要为每种类型缓存这样的序列化器,以避免每个创建的实例的内存泄漏.
创建自己的XmlSerializer工厂并简单地使用它:
XmlSerializer serializer = XmlSerializerFactoryNoThrow.Create(typeof(MyType));
Run Code Online (Sandbox Code Playgroud)
工厂看起来像:
public static class XmlSerializerFactoryNoThrow
{
public static Dictionary<Type, XmlSerializer> _cache = new Dictionary<Type, XmlSerializer>();
private static object SyncRootCache = new object();
/// <summary>
/// //the constructor XmlSerializer.FromTypes does not throw exception, but it is said that it causes memory leaks
/// http://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor
/// That is why I use dictionary to cache the serializers my self.
/// </summary>
public static XmlSerializer Create(Type type)
{
XmlSerializer serializer;
lock (SyncRootCache)
{
if (_cache.TryGetValue(type, out serializer))
return serializer;
}
lock (type) //multiple variable of type of one type is same instance
{
//constructor XmlSerializer.FromTypes does not throw the first chance exception
serializer = XmlSerializer.FromTypes(new[] { type })[0];
//serializer = XmlSerializerFactoryNoThrow.Create(type);
}
lock (SyncRootCache)
{
_cache[type] = serializer;
}
return serializer;
}
}
Run Code Online (Sandbox Code Playgroud)
更复杂的版本没有内存泄漏的可能性(请有人查看代码):
public static XmlSerializer Create(Type type)
{
XmlSerializer serializer;
lock (SyncRootCache)
{
if (_cache.TryGetValue(type, out serializer))
return serializer;
}
lock (type) //multiple variable of type of one type is same instance
{
lock (SyncRootCache)
{
if (_cache.TryGetValue(type, out serializer))
return serializer;
}
serializer = XmlSerializer.FromTypes(new[] { type })[0];
lock (SyncRootCache)
{
_cache[type] = serializer;
}
}
return serializer;
}
}
Run Code Online (Sandbox Code Playgroud)