7

在我的 Visual Studio 2010 项目中,我使用以下 Post-Build 事件命令行来使用 sgen 创建 XmlSerializers.dll。

构建后事件:

"$(ProgramFiles)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" /a:"$(TargetPath)" /c:/keyfile:"c:\myproject\mykey.snk" /f

我的项目是强命名的,所以使用相同的键来强命名“XmlSerializers.dll”。VS 在输出文件夹中创建 XmlSerializers.dll。

但是,我注意到使用 ProcessMonitor,.NET 仍然在运行时调用 CSC.exe。我遇到了这篇文章,用户有类似的问题并通过使用 XmlSerializer(Type) 构造函数解决。

我在代码中使用了相同的技术,但它仍然调用 csc.exe:

var fs = new FileStream(SettingsFilePath, FileMode.Open);
try
{
var serializer = new XmlSerializer(typeof(AppSettings));
settings = (AppSettings)serializer.Deserialize(fs);
}
finally
{
fs.Close();
}

由于性能原因,我需要使用预编译的 XML 序列化,而且我有时会在 Windows 关闭时看到 csc.exe 错误。我的应用程序在 Form 关闭时保存数据,在关机期间它失败了,因为 Windows 不允许在关机序列期间启动新进程。我已经看到通过预编译 XML 序列化来解决这个问题的建议。

关于为什么 XmlSerializer 不使用由 sgen 创建的 XmlSerializers.dll 的任何建议?

谢谢。

4

3 回答 3

4

问题可能是不同的目标平台:默认情况下sgen使用“任何 CPU”(MSIL),如果包含要反序列化或序列化的类型的程序集是为 x86 或 x64 编译的,它不会加载.XmlSerializers.dll

更一般地说,我查看了加载序列化程序集的 .NET 代码 - 这是一些重现与单元测试相同行为的代码:

/// <summary>Generates an identifier for the assembly of a specified type</summary>
/// <remarks>Code copied from the .NET serialization classes - to emulate the same bahavior</remarks>
/// <param name="type">The type</param>
/// <returns>String identifying the type's assembly</returns>
static string GenerateAssemblyId(Type type) 
{ 
  Module[] modules = type.Assembly.GetModules();
  ArrayList list = new ArrayList();
  for (int i = 0; i < modules.Length; i++) {
    list.Add(modules[i].ModuleVersionId.ToString()); 
  }
  list.Sort(); 
  StringBuilder sb = new StringBuilder(); 
  for (int i = 0; i < list.Count; i++) {
    sb.Append(list[i].ToString()); 
    sb.Append(",");
  }
  return sb.ToString();
} // GenerateAssemblyId

/// <summary>Verifies that the serialization assembly for the specified type can be loaded</summary>
/// <remarks>Code copied from the .NET serialization classes - to emulate the same behavior and tests</remarks>
/// <param name="type">The type</param>
static void AssertCanLoadXmlSerializers(Type type)
{
  if (type == null)
    throw new ArgumentNullException("type");
  Assembly serializerAssembly = null;
  // Create the name of the XML serilizers assembly from the type's one
  AssemblyName name = type.Assembly.GetName(true); 
  name.Name = name.Name + ".XmlSerializers"; 
  name.CodeBase = null;
  name.CultureInfo = CultureInfo.InvariantCulture;
  try {
    serializerAssembly = Assembly.Load(name);
  } catch (Exception e) {
    Assert.Fail("Unable to load XML serialization assembly for type '{0}': {1}", type.FullName, e.Message);
  }
  object[] attrs = serializerAssembly.GetCustomAttributes(typeof(XmlSerializerVersionAttribute), false);
  if (attrs == null || attrs.Length == 0) {
    Assert.Fail(
      "Unable to use XML serialization assembly '{1}' for type '{0}': it does not contain XmlSerializerVersionAttribute", 
      type.FullName, 
      serializerAssembly.FullName
    );
  }
  if (attrs.Length > 1) {
    Assert.Fail(
      "Unable to use XML serialization assembly '{1}' for type '{0}': it contains multiple XmlSerializerVersionAttribute", 
      type.FullName, 
      serializerAssembly.FullName
    );
  }
  XmlSerializerVersionAttribute assemblyInfo = (XmlSerializerVersionAttribute)attrs[0];
  string assemblyId = GenerateAssemblyId(type);
  if (assemblyInfo.ParentAssemblyId != assemblyId) {
    Assert.Fail(
      "Unable to use XML serialization assembly '{1}' for type '{0}': it does not match assembly id '{2}'", 
      type.FullName, 
      serializerAssembly.FullName,
      assemblyId
    );
  }
} // AssertCanLoadXmlSerializers

只需调用AssertCanLoadXmlSerializers()传递类型而不是需要序列化/反序列化。如果未加载序列化程序集,您可以从错误消息中很好地了解原因。

我将它添加到我们的单元测试中,以便我可以合理地确定序列化程序集是好的。

于 2012-12-08T02:08:29.277 回答
0

您是否尝试过在生成的 dll 上运行ngen.exe

跑步

ngen.exe install myproject.XmlSerializers.dll

将在图像缓存中安装 dll 的本机图像,该图像应在运行时使用,而不是调用 JIT 编译器。

于 2012-05-09T16:16:53.357 回答
0

您确定序列化程序集已正确签名吗?通常你需要转义引号。请参阅此处了解更多信息。

您还可以检查 ID 是否匹配。如果您在构建序列化程序集后修改源程序集,则 ID 将不再匹配,并且将不会使用序列化程序集。请参阅此处了解更多信息。

如果一切正确:禁用工具->选项->调试->“仅启用我的代码”并启用调试->异常->公共语言运行时异常->抛出。然后将您的应用程序调试到完成序列化的地步。将抛出第一次机会异常,说明为什么不能使用序列化程序集。

于 2013-02-13T07:04:55.033 回答