C# 由于KnownType,无法反序列化多态字典json“__“类型”;问题

C# 由于KnownType,无法反序列化多态字典json“__“类型”;问题,c#,.net,types,polymorphism,datacontractjsonserializer,C#,.net,Types,Polymorphism,Datacontractjsonserializer,我创建了一个带有多态值的字典,在其中保存了一个类对象。我已经成功地序列化了JSON。但我无法反序列化它。它给出了以下错误: 元素“:Value”包含“:Sale”数据合约的数据。反序列化程序不知道映射到此协定的任何类型 如果将JSON属性“\uuu type”替换为“type”,则它可以工作,但无法恢复正确的对象类型。在序列化之前,它包含我的类类型的对象,但在反序列化之后,它包含一个system.object 我的代码如下: using System; using System.Collecti

我创建了一个带有多态值的字典,在其中保存了一个类对象。我已经成功地序列化了JSON。但我无法反序列化它。它给出了以下错误:

元素“:Value”包含“:Sale”数据合约的数据。反序列化程序不知道映射到此协定的任何类型

如果将JSON属性
“\uuu type”
替换为
“type”
,则它可以工作,但无法恢复正确的对象类型。在序列化之前,它包含我的类类型的对象,但在反序列化之后,它包含一个
system.object

我的代码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        dict.Add("employee","john");
        dict.Add("sale",new Sale(9,5243));
        dict.Add("restaurant",new Restaurant("Cheese Cake Factory", "New York"));
        //  Console.Write(dict["sale"]);

        //Code for JSON
        DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(Dictionary<string, object>));  
        MemoryStream msObj = new MemoryStream();  
        js.WriteObject(msObj, dict);  
        msObj.Position = 0;  
        StreamReader sr = new StreamReader(msObj);  
        string json = sr.ReadToEnd();  
        sr.Close();  
        msObj.Close();

        // Decode the thing
        Console.Write(json);

        Dictionary<string, object> result = new Dictionary<string, object>();
        using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Dictionary<string, object>));
            result = serializer.ReadObject(stream) as Dictionary<string, object>;
        }
    }
}

[DataContract]
[KnownType(typeof(Sale))]
public class Sale 
{
    [DataMember(Name = "SaleId")]
    public int SaleId {get; set;}
    [DataMember(Name = "Total")]
    public int Total{ get; set;}

    public Sale(int saleid, int total)
    {
        SaleId = saleid;
        Total = total;
    }

    public int getTotal()
    {
        return  Total;
    }
}

[DataContract(Name = "Restaurant", Namespace="")]
[KnownType(typeof(Restaurant))]
public class Restaurant
{
    [DataMember(EmitDefaultValue = false)]
    public string Name {get; set;}
    [DataMember(EmitDefaultValue = false)]
    public string City{get; set;}

    public Restaurant(string name, string city)
    {
        Name = name;
        City = city;
    }
}
使用系统;
使用System.Collections.Generic;
使用系统文本;
使用System.IO;
使用System.Runtime.Serialization;
使用System.Runtime.Serialization.Json;
班级计划
{
静态void Main(字符串[]参数)
{
Dictionary dict=新字典();
dict.Add(“雇员”、“约翰”);
添加(“销售”,新销售(95243));
dict.Add(“餐厅”,新餐厅(“奶酪蛋糕工厂”,“纽约”);
//Console.Write(dict[“sale”]);
//JSON的代码
DataContractJsonSerializer js=新的DataContractJsonSerializer(typeof(Dictionary));
MemoryStream msObj=新的MemoryStream();
js.WriteObject(msObj,dict);
msObj.Position=0;
StreamReader sr=新的StreamReader(msObj);
字符串json=sr.ReadToEnd();
高级关闭();
msObj.Close();
//破译
Console.Write(json);
字典结果=新字典();
使用(MemoryStream stream=new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
DataContractJsonSerializer serializer=新的DataContractJsonSerializer(typeof(Dictionary));
结果=serializer.ReadObject(流)作为字典;
}
}
}
[数据合同]
[知识类型(类型(销售))]
公务舱销售
{
[数据成员(Name=“SaleId”)]
public int SaleId{get;set;}
[DataMember(Name=“Total”)]
公共整数总计{get;set;}
公开销售(国际销售额,国际总额)
{
SaleId=SaleId;
总计=总计;
}
公共int getTotal()
{
返回总数;
}
}
[DataContract(Name=“Restaurant”,Namespace=”“)]
[知识类型(类型(餐厅))]
公共餐厅
{
[数据成员(EmitDefaultValue=false)]
公共字符串名称{get;set;}
[数据成员(EmitDefaultValue=false)]
公共字符串City{get;set;}
公共餐厅(字符串名称、字符串城市)
{
名称=名称;
城市=城市;
}
}

小提琴链接:

你遇到的问题是你把
[KnownType(typeof(…)]]
放在
销售
餐厅
上面

使用KnownType的原因是为了在1和其他对象之间进行转换。因此,反序列化程序不知道
Sale
对象的一个已知类型。所以它不能将对象转换为销售

仅当字典中的所有项共享一个公共父对象时,此操作才有效,如下所示:

    [KnownType(typeof(Sale))]
    [KnownType(typeof(Restaurant))]
    [KnownType(typeof(Employee))]
    [DataContract]
    public class SomeObject {

    }

    [DataContract(Name = "Sale", Namespace="")]
    public class Sale : SomeObject
    {
       //methods + properties + variables
    }

    [DataContract(Name = "Restaurant", Namespace="")]
    public class Restaurant : SomeObject
    {
        //methods + properties + variables   
    }

    [DataContract(Name = "Employee", Namespace="")]
    public class Employee: SomeObject
    {
        //methods + properties + variables   
    }

然后用字典作为参考

Dictionary<string, SomeObject> dict = new Dictionary<string, SomeObject>();
Dictionary dict=new Dictionary();

您正试图序列化具有多态成员的根对象
字典。数据协定序列化程序对多态性使用白名单方法:在序列化期间遇到的所有多态子类型必须在序列化图中遇到该子类型的实例之前通过该机制声明

那么,如何使用您的数据模型实现这一点呢?有几种方法:

  • 直接添加到静态声明的基类型,如中所示

    这在这里不起作用,因为基本类型是
    对象
    ,您不能修改它

  • [KnownType(typeof(TDerivedObject))]
    添加到序列化图中的某个父对象

    这看起来有问题,因为您的根对象类型是
    Dictionary
    ,但是您可以对Dictionary进行子类化以获得所需的结果:

    [KnownType(typeof(Sale))]
    [KnownType(typeof(Restaurant))]
    public class ObjectDictionary : Dictionary<string, object>
    {
    }
    
    演示小提琴#1

  • 通过序列化程序在运行时使用中指定的已知类型配置其他已知类型:


    有关更多信息,请参见。

    感谢您提供快速解决方案。它运转良好。我已经更新了小提琴。但我无法添加非对象。你知道吗?这样我也可以在下面添加。dict.Add(“雇员”、“约翰”);它还需要是一个扩展
    SomeObject
    的对象,我稍微编辑了一下我的答案
    var dict = new ObjectDictionary()
    {
        { "employee","john" },
        {"sale",new Sale(9,5243) },
        {"restaurant",new Restaurant("Cheese Cake Factory", "New York")},
    };
    
    DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(ObjectDictionary));  
    
    var settings = new DataContractJsonSerializerSettings
    {
        KnownTypes = new [] { typeof(Sale), typeof(Restaurant) },
    };
    DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(Dictionary<string, object>), settings);  
    
    [DataContract]
    //[KnownType(typeof(Sale))] Remove this
    public class Sale 
    {
        // Remainder unchanged
    }