意外的Xml到DataSet的转换

时间:2018-07-11 14:25:27

标签: c# serialization dataset

我上了汽车课

[Serializable]
public class Car
{
    public Driver Driver = new Driver();
    public List<Driver> Drivers = new List<Driver>();
}

[Serializable]
public class Driver
{
    public int Id { get; set; }
}

当我尝试序列化此类的一个象元然后转换为数据集时,我得到了一个非常奇怪的行为:

void Main()
{
    var x = new Car();
    x.Drivers.Add(new Driver { Id = 1 });
    var dataSet= AsDataSet(x);
    dataSet.Tables["Driver"].Rows.Count;//2!! and two columns: Id and Driver_Id
    dataSet.Tables["Drivers"].Rows.Count;//1    and only one column Driver_Id
}

static DataSet AsDataSet(Car ceInv)
{
    var serializer = new XmlSerializer(ceInv.GetType());
    var ms = new MemoryStream();
    serializer.Serialize(ms, ceInv);
    ms.Position = 0;
    var ds = new DataSet();
    ds.ReadXml(ms);
    return ds;
}

有人可以告诉我为什么表Drivers为空并且没有ID列吗? 不幸的是,属性Driver应该保持这种状态(旧版代码)。我只能更改属性Drivers。 更改驱动程序属性的名称不会对结果产生影响。

2 个答案:

答案 0 :(得分:0)

看看您的DataSet的序列化表示形式,这应该很明显。

<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Driver>
    <Id>0</Id>
  </Driver>
  <Drivers>
    <Driver>
      <Id>1</Id>
    </Driver>
  </Drivers>
</Car>

您如何期望ReadXml()方法区分第一个<Driver>元素和<Drivers>元素内的元素?它们似乎是同一张表的一部分。

您还将在Driver类中使用空Car实例化一个新的Id,不确定是否是故意的。

无论如何,我会让您的属性名称不那么模棱两可,以便ReadXml()可以解决问题。例如,将Driver中的单个Car属性更改为PrimaryDriver或类似名称。

我知道您说您不能更改该属性,所以唯一的解决方案是自定义XML序列化程序,但这可能无法为您提供所需的DataSet

void Main()
{
    var x = new Car();
    x.Drivers.Add(new Driver { Id = 1 });
    var dataSet = AsDataSet(x);
    Console.WriteLine($"PrimaryDriver: {dataSet.Tables["PrimaryDriver"].Rows.Count}");
    Console.WriteLine($"Drivers: {dataSet.Tables["Drivers"].Rows.Count}");

    // Output:
    // PrimaryDriver: 1
    // Drivers: 1
}

[Serializable]
public class Car
{
    public Driver PrimaryDriver = new Driver();
    public List<Driver> Drivers = new List<Driver>();
}

[Serializable]
public class Driver
{
    public int Id { get; set; }
}

private static DataSet AsDataSet(Car ceInv)
{
    var serializer = new XmlSerializer(ceInv.GetType());
    var ms = new MemoryStream();
    serializer.Serialize(ms, ceInv);
    ms.Position = 0;
    var ds = new DataSet();
    //Console.WriteLine($"{new StreamReader(ms).ReadToEnd()}"); ms.Position = 0; // DEBUGGING
    ds.ReadXml(ms);
    return ds;
}

答案 1 :(得分:0)

根据我在重命名Car类中的一个/两个属性后所看到的内容,看来ReadXml()会根据使用的类型而不只是属性来推断架构。考虑以下;将Car的定义更改为

之后
[Serializable]
public class Car
{
    public Driver Someone { get; set; } = new Driver { Id = 47 }; // I did this so I could identify the rows
    public List<Driver> Dudes { get; set; } = new List<Driver>(); 
}

我最终在数据集中得到了3个表。有人,帅哥和司机。单个属性按预期存储在为该属性命名的表中。另一方面,list属性会创建一个以该类型命名的表,在本例中为Driver,在您的情况下是另一个以属性Drivers命名的表,在我的情况下为Dudes

List<Driver>属性的数据存储在驱动程序表中。该属性与以该属性命名的表之间存在关系。