序列化/反序列化源自Treenode的

时间:2017-02-07 12:44:23

标签: c# xml serialization deserialization treenode

我有两个班级,“公司”派生自Treenode,“文件”。

[Serializable]
[XmlRoot("Company")]
public class Company : TreeNode, IXmlSerializable
{
    private string _x;
    private string _y;

    public Company() { }

    [XmlElement("X")]
    public string X { get; set; }
    [XmlElement("Y")]
    public string Y { get; set; }


    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }
    public void ReadXml(XmlReader reader)
    {
        if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "Company")
        {
            x = reader["X"].ToString;
            y = reader["Y"].ToString;           
        }
    }
    public void WriteXml(XmlWriter writer)
    {
        writer.WriteElementString("X", this.X.ToString());
        writer.WriteElementString("Y", this.Y.ToString());
    }
}

public class Document
{
    private int _id;
    private string _name;
    private Company _company;

    public Document() { }

    [XmlElement("ID")]
    public int ID { get; set; }
    [XmlElement("Name")]
    public string Name { get; set; }
    [XmlElement("Company")]
    public Company Comp { get; set; }
}

当我尝试序列化文档,然后保存到文件,它的工作。但是当我反序列化时,reader参数始终为null。任何解决方案?

这是我的反序列化代码。 “sr”是包含xml文本的变量。

var sr = new StreamReader(ms);
var myStr = sr.ReadToEnd();

XmlSerializer serializer = new XmlSerializer(typeof(List<Document>));
using (TextReader tr = new StringReader(myStr))
{
    List<Document> docu = (List<Document>)serializer.Deserialize(tr);
}

我尝试实现ISerialization和debug但从未触发过,并尝试覆盖序列化和反序列化方法,但没有运气。

我正在使用.NET Framework 3.5

1 个答案:

答案 0 :(得分:2)

this article中所述,正确实施IXmlSerializable实际上非常棘手。您ReadXml()的实现似乎违反了它使用包装元素本身以及所有内容的要求,如下所示:

public void ReadXml(System.Xml.XmlReader reader)
{
    reader.MoveToContent();
    // Read attributes
    Boolean isEmptyElement = reader.IsEmptyElement; // (1)
    reader.ReadStartElement();
    if (!isEmptyElement) // (1)
    {
        // Read Child elements X and Y

        // Consume the end of the wrapper element
        reader.ReadEndElement();
    }
}

此外,reader["X"]会返回名为"X" XML属性的值,如docs中所述。在WriteXml()中,您将XY的值写为嵌套的 XML元素。这解释了NullReferenceException。您需要修复读写方法以保持一致。

但是,我建议实施IXmlSerializable的替代方案,即为Company引入代理类型。首先,extractTreeNode Companypublic interface ICompany { string X { get; set; } string Y { get; set; } } public class Company : TreeNode, ICompany { public Company() { } public string X { get; set; } public string Y { get; set; } } 属性添加到接口中:

TreeNode

这是可选的,但使代码更清晰。接下来,介绍一个代理POCO,它实现相同的接口但不从public class CompanySurrogate : ICompany { public string X { get; set; } public string Y { get; set; } public static implicit operator CompanySurrogate(Company company) { if (company == null) return null; // For more complex types, use AutoMapper return new CompanySurrogate { X = company.X, Y = company.Y }; } public static implicit operator Company(CompanySurrogate surrogate) { if (surrogate == null) return null; // For more complex types, use AutoMapper return new Company { X = surrogate.X, Y = surrogate.Y }; } } 继承:

Company

请注意,代理可以隐式转换为原始public class Document { public Document() { } [XmlElement("ID")] public int ID { get; set; } [XmlElement("Name")] public string Name { get; set; } [XmlElement("Company", Type = typeof(CompanySurrogate))] public Company Comp { get; set; } } 类型?现在,您可以通过将XmlElementAttribute.Type属性属性设置为代理项属性来使用XML序列化中的代理项:

IXmlSerializable

这避免了实施var list = new List<Document> { new Document { Name = "my name", ID = 101, Comp = new Company { X = "foo", Y = "bar", NodeFont = new System.Drawing.Font("Arial", 10) } }, new Document { Name = "2nd name", ID = 222, Comp = new Company { X = "tlon", Y = "ukbar" } }, }; 时出现的所有错误。给出以下输入列表:

<ArrayOfDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Document>
        <ID>101</ID>
        <Name>my name</Name>
        <Company>
            <X>foo</X>
            <Y>bar</Y>
        </Company>
    </Document>
    <Document>
        <ID>222</ID>
        <Name>2nd name</Name>
        <Company>
            <X>tlon</X>
            <Y>ukbar</Y>
        </Company>
    </Document>
</ArrayOfDocument>

可以生成以下XML,并且可以成功反序列化:

Company

话虽如此,我并不是真的推荐这种设计。您的UI应该呈现您的数据模型,它不应该 您的数据模型。例如,请参阅How does one implement UI independent applications?。尽可能用ICompany替换TreeNode可能是改变设计的第一步;您可能会发现使用public class CompanyNode : TreeNode { public ICompany Company { get; set; } } 替换现有体系结构变得更加容易,如下所示:

<?php

include ('session_start.php');
include_once('db_connect_universal.php');

$user_id = $_SESSION['sess_id'];

//GET USER FRIENDS AND DETAILS
$get_friends = "SELECT * FROM citizens
                INNER JOIN user_details 
                ON citizens.citizenID=user_details.UserID 
                WHERE citizens.userID = '".$user_id."'";

$results_get_friends = $conn->query($get_friends);

$num_rows_friends = mysqli_num_rows ($results_get_friends);

while ($row_friends = $results_get_friends->fetch_assoc()) {

    $citizenID = $row_friends['citizenID'];

    //GET RATINGS AND COMMENTS
    $sql = "SELECT * FROM comments
                INNER JOIN organiser ON comments.movieID=organiser.movieID 
            WHERE comments.userID= '".$citizenID."'  
              AND ratings_n_comments.Time BETWEEN DATE_SUB(CURDATE(), INTERVAL 28 DAY) 
                                              AND DATE_ADD(CURDATE(), INTERVAL 10 DAY)
            ORDER BY comments.Time DESC";

    $result = $conn->query($sql);

    $num_rows = mysqli_num_rows ($result);

    $row = $result->fetch_assoc(); 

    $n_Rating[]= array(
                        'dp' => $row_friends['display_pics'],
                        'uname' => $row_friends['Uname'],
                        'poster'=> $row['mooster'],
                        'title'=> $row['moitle'],
                        'genre'=> $row['moenre'],
                        'comment'=> $row['Comment'],
                        'mid'=> $row['mID'],
                        'check' => 'data'
                    );
}

header('Content-Type: application/json');
echo json_encode ($n_Rating);

}

//detailed error reporting
if (!$sql) {
    echo 'MySQL Error: ' . mysqli_error($conn);
    exit;
}
?>