Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用DataContractJsonSerializer将JSON反序列化为抽象列表_C#_Json_List_Serialization_Abstract - Fatal编程技术网

C# 使用DataContractJsonSerializer将JSON反序列化为抽象列表

C# 使用DataContractJsonSerializer将JSON反序列化为抽象列表,c#,json,list,serialization,abstract,C#,Json,List,Serialization,Abstract,我试图将JSon文件反序列化为包含抽象列表的类的实例。将实例序列化为Json效果很好(请查看下面的Json文件)。反序列化时,我得到一个“System.MemberAccessException”,消息为“CannotcreateasAbstractClass”。显然,反序列化程序试图实例化抽象类而不是具体类 在我的示例中,反序列化的类称为ElementContainer: namespace Data { [DataContract] [KnownType(typeof(Ele

我试图将JSon文件反序列化为包含抽象列表的类的实例。将实例序列化为Json效果很好(请查看下面的Json文件)。反序列化时,我得到一个“System.MemberAccessException”,消息为“CannotcreateasAbstractClass”。显然,反序列化程序试图实例化抽象类而不是具体类

在我的示例中,反序列化的类称为ElementContainer:

namespace Data
{
    [DataContract]
    [KnownType(typeof(ElementA))]
    [KnownType(typeof(ElementB))]
    public class ElementContainer
    {
        [DataMember]
        public List<Element> Elements { get; set; }
    }

    [DataContract]
    public abstract class Element
    {
    }

    [DataContract]
    public class ElementA : Element
    {
        [DataMember]
        int Id { get; set; }
    }

    [DataContract]
    public class ElementB : Element
    {
        [DataMember]
        string Name { get; set; }
    }
}
以下是我用于反序列化的代码:

    public T LoadFromJSON<T>(string filePath)
    {
        try
        {
            using (FileStream stream = File.OpenRead(filePath))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
                T contract = (T)serializer.ReadObject(stream);
                return contract;
            }
        }
        catch (System.Exception ex)
        {
            logger.Error("Cannot deserialize json " + filePath, ex);
            throw;
        }
    }
public T LoadFromJSON(字符串文件路径)
{
尝试
{
使用(FileStream-stream=File.OpenRead(filePath))
{
DataContractJsonSerializer serializer=新的DataContractJsonSerializer(typeof(T));
T contract=(T)serializer.ReadObject(流);
退货合同;
}
}
catch(System.Exception-ex)
{
logger.Error(“无法反序列化json”+filePath,ex);
投掷;
}
}
有可能使反序列化工作吗


谢谢

我们已经找到了它不起作用的原因。在对象序列化之后,我们识别结果字符串以提高可读性。然后我们将字符串写入一个文件:

    public void SaveContractToJSON<T>(T contract, string filePath)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            serializer.WriteObject(stream, contract);
            string json = Encoding.UTF8.GetString(stream.ToArray());
            File.WriteAllText(filePath, json.IndentJSON());
        }
    }
但下一个字符串将不会序列化

"{\"Elements\":[   {\"__type\":\"ElementA:#Data\",\"Id\":1}]}"
唯一的区别是“\uuu type”前面的空格字符。序列化将引发MemberAccessException。这是误导性的,因为这种行为仅在反序列化到抽象列表时出现。不管字符是什么,序列化到抽象字段都可以很好地工作

要在不删除文件可读性的情况下修复此问题,可以在反序列化之前修改字符串。例如:

    public T LoadContractFromJSON<T>(string filePath)
    {
        try
        {
            string text = File.ReadAllText(filePath);
            text  = Regex.Replace(text, "\\{[\\n\\r ]*\"__type", "{\"__type");
            using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
                T contract = (T)serializer.ReadObject(stream);
                return contract;
            }
        }
        catch (System.Exception ex)
        {
            logger.Error("Cannot deserialize json " + filePath, ex);
            throw;
        }
    }
public T LoadContractFromJSON(字符串文件路径)
{
尝试
{
string text=File.ReadAllText(文件路径);
text=Regex.Replace(text,“\{[\\n\\r]*\”\uuu类型“,“{\”\uu类型”);
使用(MemoryStream stream=new MemoryStream(Encoding.UTF8.GetBytes(text)))
{
DataContractJsonSerializer serializer=新的DataContractJsonSerializer(typeof(T));
T contract=(T)serializer.ReadObject(流);
退货合同;
}
}
catch(System.Exception-ex)
{
logger.Error(“无法反序列化json”+filePath,ex);
投掷;
}
}

您是否尝试过将列表类型更改为object并查看发生了什么情况?我尝试过,但没有改变任何内容。
\{[\\n\\r]*\“\uu type
发布的模式是危险的,它会歧视在
\uu type
之前序列化的任何属性或拾取任何包含文本的属性。”__键入,并对空格和特定于平台的换行符序列使用隐式空格,而不是显式的
\s
。\u类型类似于DataContractJsonSerializer的关键字。它必须放在任何其他字段之前(实际上是放在任何其他字符之前)否则json不会以正确的类型进行序列化。关于特定于平台的字符,我将对此进行更改。谢谢。简单地将_类型作为对象的第一个属性对我来说很有效。在反序列化之前,不需要用正则表达式替换。我遇到了类似的问题,但仅在生产中。在本地,使用相同的数据库和代码,我工作正常。可能是某些设置导致它在一个环境中插入空格,而不是在另一个环境中插入空格?
"{\"Elements\":[   {\"__type\":\"ElementA:#Data\",\"Id\":1}]}"
    public T LoadContractFromJSON<T>(string filePath)
    {
        try
        {
            string text = File.ReadAllText(filePath);
            text  = Regex.Replace(text, "\\{[\\n\\r ]*\"__type", "{\"__type");
            using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
                T contract = (T)serializer.ReadObject(stream);
                return contract;
            }
        }
        catch (System.Exception ex)
        {
            logger.Error("Cannot deserialize json " + filePath, ex);
            throw;
        }
    }