每当序列化数据包含派生类型时,只要尝试从json反序列化类,都会出错。我的最终目标是能够存储各种派生类型,所以这是一个问题。当我在序列化的对象中仅存储非派生类型时,不会发生该错误。对于添加的上下文,该代码是使用Revit的AddinManager扩展运行的加载项的一部分。
(根据建议,我重新编写了代码以尝试找出问题并给出更易于理解的描述。我已将代码更改为使用两个简单的类。)
更改后,我现在收到错误:
在JSON'AddinNamespace.ToyNodePlus,AddinAssemblyName,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'中指定的类型与'AddinNamespace.ToyNode,AddinAssembly,Version = 1.0.0.0,Culture = neutral,PublicKeyToken =空值'。路径“ TestNode。$ type”,第1行,位置61。
AddinSettings
namespace AddinNamespace
{
public class AddinSettings
{
public const string Filename = "AddinSettings.json";
public ToyNode TestNode;
}
}
ToyNode和ToyNodePlus定义
namespace AddinNamespace
{
public class ToyNode
{
public string Name;
}
public class ToyNodePlus : ToyNode
{
public int AdditionalValue;
}
}
序列化代码
private JsonSerializerSettings serializerSettings = null;
private void OnAddinStart(){
serializerSettings = new JsonSerializerSettings()
{
TypeNameHandling=TypeNameHandling.Auto,
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
};
if(File.Exists(AddinSettings.Filename)){
string fileContents = File.ReadAllText(AddinSettings.Filename);
AddinSettings settings = JsonConvert.DeserializeObject<AddinSettings> (fileContents, serializerSettings);
//do work with settings here
}
}
//code for saving to Json (code appears to be working as expected)
private void OnAddinFinish(){
AddinSettings settings = new AddinSettings();
settings.TestNode = new ToyNodePlus() {AdditionalValue = 7, Name= "This is a test" };
string fileContents = JsonConvert.SerializeObject(settings, serializerSettings);
File.WriteAllText(AddinSettings.Filename, fileContents);
}
创建的Json文件内容
{"TestNode":{"$type":"AddinNamespace.ToyNodePlus, AddinAssembly","AdditionalValue":7,"Name":"This is a test"}}
我想我找到了答案。实际上,我不得不查看github上的source code来找到答案,但最终我能够找出错误发生在哪一行。
此特定错误是由触发以下检查的JsonSerializerInternalReader.ResolveTypeName(..)中的检查引发的]
!objectType.IsAssignableFrom(specifiedType)
调查错误最终导致了此stackoverflow post。我的情况下的特定问题是由于我的代码被作为类库调用,并且调用的应用程序在第一次调用后将旧的.dll文件缓存在temp文件夹中而引起的。因为dll在技术上不同
Type.IsAssignable(Type)
返回了false。
我最终不得不编写一个自定义的SerializationBinder并将其添加到JsonSerializerSettings参数中,以确保使用一致的程序集。 (下面的实现)。我不确定这是否是最好的处理方式,所以如果有人有其他替代解决方案或改进...
class CustomSerializationBinder : ISerializationBinder
{
private Dictionary<string, Assembly> assemblyLookup = new Dictionary<string, Assembly>();
private Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
public CustomSerializationBinder(List<Assembly> problemAssemblies = null)
{
if (problemAssemblies == null) problemAssemblies = new List<Assembly>();
foreach(Assembly assembly in problemAssemblies)
{
if(!assemblyLookup.ContainsKey(assembly.GetName().Name))
this.assemblyLookup.Add(assembly.GetName().Name,assembly);
}
foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if(!assemblyLookup.ContainsKey(assembly.GetName().Name))
assemblyLookup.Add(assembly.GetName().Name, assembly);
}
}
public void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = serializedType.Assembly.FullName;
typeName = serializedType.FullName;
}
public Type BindToType(string assemblyName, string typeName)
{
Type resolvedType;
Assembly resolvedAssembly;
typeCache.TryGetValue(typeName, out resolvedType);
if (resolvedType != null) return resolvedType;
assemblyLookup.TryGetValue(assemblyName, out resolvedAssembly);
if (resolvedAssembly == null) return null;
resolvedType = resolvedAssembly.GetType(typeName);
if (resolvedType != null)
typeCache.Add(typeName, resolvedType);
return resolvedType;
}
}