C#将不同接口实现的JSON列表反序列化为一个列表,而不会丢失数据

C#将不同接口实现的JSON列表反序列化为一个列表,而不会丢失数据,c#,json,deserialization,C#,Json,Deserialization,我能够成功地将包含Employee和Manager对象的混合列表序列化为JSON 但是,当我尝试将JSON反序列化回列表时,我将丢失子类中的所有字段数据,并且当我尝试强制转换到任何一个子类时,我会得到一个空值。如何反序列化这些用户的列表而不丢失Employee和Manager子类字段中的数据 [DataContract] public class User { [DataMember] public string FirstName { get; set; } [DataMember

我能够成功地将包含Employee和Manager对象的混合列表序列化为JSON

但是,当我尝试将JSON反序列化回列表时,我将丢失子类中的所有字段数据,并且当我尝试强制转换到任何一个子类时,我会得到一个空值。如何反序列化这些用户的列表而不丢失Employee和Manager子类字段中的数据

[DataContract]
public class User {
  [DataMember]
  public string FirstName { get; set; }
  [DataMember]
  public string LastName { get; set; }
}

[DataContract]
public class Employee : User {
  [DataMember]
  public string JobTitle { get; set; }
}  

[DataContract]
public class Manager : User {
  [DataMember]
  public string Department { get; set; }
} 
EDIT——这是我的反序列化代码:

// abridged
public void Client() {
  var jsonContent = jsonResponse.Content;
  var entityList = Deserialize<IEnumerable<T>>(new JsonMediaTypeFormatter(), jsonContent);
}

protected T Deserialize<T>(MediaTypeFormatter formatter, string str) where T : class {
    // Write the serialized string to a memory stream.
    Stream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write(str);
    writer.Flush();
    stream.Position = 0;
    // Deserialize to an object of type T
    return formatter.ReadFromStreamAsync(typeof(T), stream, null, null).Result as T;
} 
//节略
公共无效客户端(){
var jsonContent=jsonResponse.Content;
var entityList=反序列化(新的JsonMediaTypeFormatter(),jsonContent);
}
受保护的T反序列化(MediaTypeFormatter格式化程序,字符串str),其中T:class{
//将序列化字符串写入内存流。
Stream=新的MemoryStream();
StreamWriter writer=新StreamWriter(流);
writer.Write(str);
writer.Flush();
流位置=0;
//反序列化为T类型的对象
返回formatter.ReadFromStreamAsync(typeof(T),stream,null,null)。结果为T;
} 

您可以使用
DataContractJsonSerializer
和一组作为序列化器构造函数参数传递的已知类型来实现这一点

我创建了一个简单的测试代码来演示:

var list = new List<User>() {
    new User { FirstName = "user1", LastName = "user1" },
    new Employee { FirstName = "employee1", LastName = "employee1", JobTitle = "employee1" },
    new Manager() { FirstName = "manager1", LastName = "manager1", Department = "manager1"}
};

var serializer = new DataContractJsonSerializer(typeof(List<User>), new [] { typeof(Employee), typeof(Manager) });

string json;
using (var stream = new MemoryStream())
{
    serializer.WriteObject(stream, list);
    stream.Position = 0;
    using(var reader = new StreamReader(stream))
    {
        json = reader.ReadToEnd();
    }
}

List<User> list2;

using(var stream = new MemoryStream())
{
    using(var writer = new StreamWriter(stream))
    {
        writer.Write(json);
        writer.Flush();
        stream.Position = 0;
        list2 = (List<User>)serializer.ReadObject(stream);
    }
}
var list=新列表(){
新用户{FirstName=“user1”,LastName=“user1”},
新员工{FirstName=“employee1”,LastName=“employee1”,JobTitle=“employee1”},
新经理(){FirstName=“manager1”,LastName=“manager1”,Department=“manager1”}
};
var serializer=newdatacontractjsonserializer(typeof(List),new[]{typeof(Employee),typeof(Manager)});
字符串json;
使用(var stream=new MemoryStream())
{
serializer.WriteObject(流,列表);
流位置=0;
使用(变量读取器=新的流读取器(流))
{
json=reader.ReadToEnd();
}
}
清单2;
使用(var stream=new MemoryStream())
{
使用(var writer=新的StreamWriter(流))
{
Write.Write(json);
writer.Flush();
流位置=0;
list2=(List)serializer.ReadObject(stream);
}
}

您可以使用
DataContractJsonSerializer
和一组作为序列化器构造函数参数传递的已知类型来实现这一点

我创建了一个简单的测试代码来演示:

var list = new List<User>() {
    new User { FirstName = "user1", LastName = "user1" },
    new Employee { FirstName = "employee1", LastName = "employee1", JobTitle = "employee1" },
    new Manager() { FirstName = "manager1", LastName = "manager1", Department = "manager1"}
};

var serializer = new DataContractJsonSerializer(typeof(List<User>), new [] { typeof(Employee), typeof(Manager) });

string json;
using (var stream = new MemoryStream())
{
    serializer.WriteObject(stream, list);
    stream.Position = 0;
    using(var reader = new StreamReader(stream))
    {
        json = reader.ReadToEnd();
    }
}

List<User> list2;

using(var stream = new MemoryStream())
{
    using(var writer = new StreamWriter(stream))
    {
        writer.Write(json);
        writer.Flush();
        stream.Position = 0;
        list2 = (List<User>)serializer.ReadObject(stream);
    }
}
var list=新列表(){
新用户{FirstName=“user1”,LastName=“user1”},
新员工{FirstName=“employee1”,LastName=“employee1”,JobTitle=“employee1”},
新经理(){FirstName=“manager1”,LastName=“manager1”,Department=“manager1”}
};
var serializer=newdatacontractjsonserializer(typeof(List),new[]{typeof(Employee),typeof(Manager)});
字符串json;
使用(var stream=new MemoryStream())
{
serializer.WriteObject(流,列表);
流位置=0;
使用(变量读取器=新的流读取器(流))
{
json=reader.ReadToEnd();
}
}
清单2;
使用(var stream=new MemoryStream())
{
使用(var writer=新的StreamWriter(流))
{
Write.Write(json);
writer.Flush();
流位置=0;
list2=(List)serializer.ReadObject(stream);
}
}

刚刚编辑了原始帖子。看起来像是JsonMediaTypeFormatter吧?您能推荐一个更好的吗?编辑以添加适当的DataContract/DataMember属性。我在我的实际代码中也使用了这些。刚刚编辑了原始文章。看起来像是JsonMediaTypeFormatter吧?您能推荐一个更好的吗?编辑以添加适当的DataContract/DataMember属性。我也在我的实际代码中使用它们。谢谢这个示例!如果我希望整个事情都是动态的,而我不知道实现类可能是什么呢?那么我认为这是不可能的。序列化程序必须搜索所有可用的名称空间,并查找继承您的
User
类的任何类。你可以自己编写这部分(使用反射)并将找到的所有内容传递到构造函数中,但我认为这不是真正有效的代码。好的,谢谢你的帮助。我试图从API客户机的角度来考虑这一点。我将返回同一列表中相同接口的这些不同实现的列表。这是一个坏习惯吗?对于不同的实现类型,人们通常会有不同的资源URL吗?这种方法的缺点似乎是,类型字段与其余数据一起序列化到JSON中。我不确定是否要将该信息公开给API客户机…感谢您提供此示例!如果我希望整个事情都是动态的,而我不知道实现类可能是什么呢?那么我认为这是不可能的。序列化程序必须搜索所有可用的名称空间,并查找继承您的
User
类的任何类。你可以自己编写这部分(使用反射)并将找到的所有内容传递到构造函数中,但我认为这不是真正有效的代码。好的,谢谢你的帮助。我试图从API客户机的角度来考虑这一点。我将返回同一列表中相同接口的这些不同实现的列表。这是一个坏习惯吗?对于不同的实现类型,人们通常会有不同的资源URL吗?这种方法的缺点似乎是,类型字段与其余数据一起序列化到JSON中。我不确定是否要将该信息公开给API客户端。。。