如何在.NET中搜索类型,忽略程序集版本?

时间:2014-01-31 20:08:47

标签: c# .net

我想在我的程序的多个版本之间保持savefile兼容性,但这会导致序列化问题,因为当我增加版本号时,程序集限定类型名称会更改,因此Type.GetType()无法找到它。有没有办法搜索忽略汇编版本的类型?

4 个答案:

答案 0 :(得分:1)

每当找不到类型时,就会触发AssembyResolvedEvent。

此事件可用于检查已加载的类型,并返回具有相同名称但忽略版本号的类型。

http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve%28v=vs.110%29.aspx

修改: 因为这是前一段时间似乎我无法正确回忆起这一切。 阿德里亚诺是对的。 AssemlyResolve只是要求组装。

因此还需要SerializationBinder。这听起来像是工作,但很简单!我会试着总结一下:

private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
  if (args == null || string.IsNullOrEmpty(args.Name))
    return null;

  //if object was serialized with previous version .dll, deserialze with current version .dll (only relevant with strong names)
  foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
  {
    if ((args.Name.StartsWith("XYZ."))  // XYZ marks my namespace
      && args.Name.Contains("Culture=neutral") && args.Name.StartsWith(ass.FullName.Split(',')[0]))
      return ass;
  }
  return null;
}

备注:这仅检查已加载的程序集!

您的SerializationBinder:

  public class XYZSerializationBinder : SerializationBinder
  {
    public override Type BindToType(string assemblyName, string typeName)
    {
      Type curType = null;
      //if object was serialized with previous version .dll, deserialze with current version .dll (only relevant with strong names)
      if (!string.IsNullOrEmpty(assemblyName) && assemblyName.Contains("Culture=neutral")
        && (assemblyName.StartsWith("XYZ.")))
      {
        string plainAssemblyName = assemblyName.Split(',')[0];
        Assembly ass = Assembly.Load(plainAssemblyName);
        curType = ass.GetType(typeName);
      }
      else
      {
        curType = Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
      }
      if (curType == null)
      {
        return typeof(InvalidType);
      }
      return curType;
    }
  }

现在只需使用活页夹!

    IFormatter formatter = new BinaryFormatter();
    formatter.Binder = serializationBinder;
    using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
      storage = formatter.Deserialize(fileStream);
    }

我希望这是你想要/需要的!

答案 1 :(得分:0)

我刚想通了!

我必须使用Type.GetType()的这个重载来自定义分辨率:

http://msdn.microsoft.com/en-us/library/ee332932(v=vs.100).aspx

我是这样做的:

type = Type.GetType(typename,
    assemblyName =>
    {
        return AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(a => a.GetName().Name == assemblyName.Name);
    },
    (assembly, typeName, caseInsensitive) =>
    {
        if (caseInsensitive)
            return assembly.GetTypes().SingleOrDefault(t => t.FullName.Equals(typeName, StringComparison.InvariantCultureIgnoreCase));
        else
            return assembly.GetTypes().SingleOrDefault(t => t.FullName == typeName);
    });

注意程序集的GetName()。Name,而不是FullName的比较。这使得只能比较程序集的实际名称,而不能比较它们的版本。

答案 2 :(得分:-1)

我想你可以使用程序集重定向:

http://msdn.microsoft.com/en-us/library/7wd6ex19(v=vs.110).aspx

答案 3 :(得分:-1)

您应该使用SerializationBinder来解析类型。

请参阅:http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder%28v=vs.110%29.aspx

请注意,使用不保存类型信息且速度更快的XML或DataContract序列化可能会更好。