Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.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# 列表中有空元素的自定义XmlSerializer问题<&燃气轮机;_C#_Xml Serialization - Fatal编程技术网

C# 列表中有空元素的自定义XmlSerializer问题<&燃气轮机;

C# 列表中有空元素的自定义XmlSerializer问题<&燃气轮机;,c#,xml-serialization,C#,Xml Serialization,我有一个需要自定义序列化程序的类。有时我会在一个列表中使用这个类,我也想序列化它。其中一些元素将为空 我可以开始工作: <MyData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Fractions> <Frac>1/2</Frac> <Frac xsi:nil=

我有一个需要自定义序列化程序的类。有时我会在一个列表中使用这个类,我也想序列化它。其中一些元素将为空

我可以开始工作:

<MyData xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Fractions>
    <Frac>1/2</Frac>
    <Frac xsi:nil="true" />
    <Frac xsi:nil="true" />
    <Frac>3/6</Frac>
  </Fractions>
</MyData>
即,在元素1和2中创建了MyFrac对象,而不是null

我是否必须为列表子类创建一个自定义序列化程序来解决这个问题,或者我是否缺少在反序列化时获取null元素的其他方法?如果是自定义序列化程序,有什么最佳方法/代码

下面我有一个完整的示例,它显示了我当前的实现

public class MyFrac : IXmlSerializable
{
    public string N;
    public string D;

    public override string ToString()
    {
        return N + "/" + D;
    }

    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
    {
        if (reader.IsEmptyElement && reader.NodeType != XmlNodeType.EndElement)
        {
            reader.Read();
            return;
        }

        reader.ReadStartElement();

        string sfrac = reader.ReadString();
        try
        {
            var m = Regex.Match(sfrac, @"(\d+)/(\d+)");
            if (!m.Success)
                throw new Exception(sfrac + " was not in the correct format");
            N = m.Result("$1");
            D = m.Result("$2");
        }
        finally
        {
            reader.ReadEndElement();
        }
    }

    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteString(N + "/" + D);
    }
}

public class MyData
{
    [XmlArrayItem("Frac")]
    public List<MyFrac> Fractions;
}

public static void Run()
{
    var data = new MyData();
    data.Fractions = new List<MyFrac>();
    data.Fractions.Add(new MyFrac { N = "1", D = "2" });
    data.Fractions.Add(null);
    data.Fractions.Add(null);
    data.Fractions.Add(new MyFrac { N = "3", D = "6" });

    var serializer = new XmlSerializer(typeof(MyData));

    StringBuilder sb = new StringBuilder();

    using (var writer = new StringWriter(sb))
    {
        serializer.Serialize(writer, data);
    }

    // Dump XML
    Console.WriteLine(sb.ToString());

    using (var reader = new StringReader(sb.ToString()))
    {
        var data2 = (MyData)serializer.Deserialize(reader);
        Console.WriteLine(data2.Fractions[0]);
        Console.WriteLine(data2.Fractions[1]);
        Console.WriteLine(data2.Fractions[2]);
        Console.WriteLine(data2.Fractions[3]);
    }
}
公共类MyFrac:IXmlSerializable
{
公共字符串N;
公共字符串D;
公共重写字符串ToString()
{
返回N+“/”+D;
}
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{
返回null;
}
void IXmlSerializable.ReadXml(System.Xml.XmlReader)
{
if(reader.IsEmptyElement&&reader.NodeType!=XmlNodeType.EndElement)
{
reader.Read();
返回;
}
reader.ReadStartElement();
string sfrac=reader.ReadString();
尝试
{
var m=Regex.Match(sfrac,@“(\d+)/(\d+));
如果(!m.Success)
抛出新异常(sfrac+“格式不正确”);
N=m.结果(“$1”);
D=m.结果($2);
}
最后
{
reader.ReadEndElement();
}
}
void IXmlSerializable.WriteXml(System.Xml.XmlWriter-writer)
{
writer.WriteString(N+“/”+D);
}
}
公共类MyData
{
[XmlArrayItem(“Frac”)]
公开名单分数;
}
公共静态无效运行()
{
var data=新的MyData();
data.fracts=新列表();
添加(新的MyFrac{N=“1”,D=“2”});
data.Fractions.Add(空);
data.Fractions.Add(空);
添加(新的MyFrac{N=“3”,D=“6”});
var serializer=newxmlserializer(typeof(MyData));
StringBuilder sb=新的StringBuilder();
使用(var编写器=新的StringWriter(sb))
{
序列化程序。序列化(写入程序、数据);
}
//转储XML
Console.WriteLine(sb.ToString());
使用(var reader=newstringreader(sb.ToString()))
{
var data2=(MyData)序列化程序。反序列化(读取器);
Console.WriteLine(data2.fracts[0]);
Console.WriteLine(数据2.分数[1]);
Console.WriteLine(数据2.分数[2]);
Console.WriteLine(数据2.分数[3]);
}
}

出现问题的原因是,在反序列化过程中,XmlSerializer首先通过调用默认构造函数创建对象,然后调用ReadXml方法设置属性值,以便ReadXml无法取消对象创建。是否需要序列化null值才能在xml中看到它?我的意思是,您可以通过使用非列表集合来避免这种情况。例如,创建自定义集合:

public class MyCollection : System.Collections.ObjectModel.Collection<MyFrac>
{
    protected override void InsertItem(int index, MyFrac item)
    {
        if(item == null) return;
        base.InsertItem(index, item);
    }       

    protected override void SetItem(int index, MyFrac item)
    {
        if(item == null) 
        {
            base.RemoveAt(index);
        }
        else
        {
            base.SetItem(index, item);
        }
    }
}
然后,序列化/反序列化按您的需要工作:

    public static void Main(string[] args)
    {
        var data = new MyData();
        data.Fractions = new MyCollection();
        data.Fractions.Add(new MyFrac { N = "1", D = "2" });
        data.Fractions.Add(null);
        data.Fractions.Add(null);
        data.Fractions.Add(new MyFrac { N = "3", D = "6" });

        var serializer = new XmlSerializer(typeof(MyData));
        StringBuilder sb = new StringBuilder();

        using (var writer = new StringWriter(sb))
        {
            serializer.Serialize(writer, data);
        }

        // Dump XML
        Console.WriteLine(sb.ToString());

        using (var reader = new StringReader(sb.ToString()))
        {
            var data2 = (MyData)serializer.Deserialize(reader);
            foreach (var element in data2.Fractions) {
                Console.WriteLine(element);
            }
        }

        Console.ReadLine();
    }
序列化xml:

<?xml version="1.0" encoding="utf-16"?>
<MyData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Fractions>
    <Frac>1/2</Frac>
    <Frac>3/6</Frac>
  </Fractions>
</MyData>

1/2
3/6
产出:

1/2

3/6

更新

好的,您需要一个具有自定义序列化规则的集合。让我们实施它:

public class MyCollection<T> : Collection<T>, IXmlSerializable where T: class 
{
    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        var serializer = new XmlSerializer(typeof(T));
        var wasEmpty = reader.IsEmptyElement;
        reader.Read();
        if (wasEmpty)
            return;
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            if (reader.IsEmptyElement)
            {
                reader.Read();
                Items.Add(null);
                continue;
            }
            var item = (T)serializer.Deserialize(reader);
            Items.Add(item);
        }
        reader.ReadEndElement();
    }

    public void WriteXml(XmlWriter writer)
    {
        var serializer = new XmlSerializer(typeof (T));
        foreach (var myFrac in Items)
        {
            serializer.Serialize(writer, myFrac);
        }
    }
}
公共类MyCollection:Collection,IXmlSerializable其中T:class
{
公共XmlSchema GetSchema()
{
返回null;
}
公共void ReadXml(XmlReader)
{
var serializer=newxmlserializer(typeof(T));
var waspempty=reader.IsEmptyElement;
reader.Read();
如果(为空)
返回;
while(reader.NodeType!=XmlNodeType.EndElement)
{
if(读卡器ISemptyelment)
{
reader.Read();
Items.Add(空);
继续;
}
var item=(T)序列化程序。反序列化(读取器);
项目。添加(项目);
}
reader.ReadEndElement();
}
public void WriteXml(XmlWriter)
{
var serializer=newxmlserializer(typeof(T));
foreach(项目中的var myFrac)
{
serializer.Serialize(writer,myFrac);
}
}
}
用法:

public class MyData
{
    public MyCollection<MyFrac> Fractions;
}

class Program
{
    static void Main(string[] args)
    {
        var data = new MyData();
        data.Fractions = new MyCollection<MyFrac>();
        data.Fractions.Add(new MyFrac { N = "1", D = "2" });
        data.Fractions.Add(null);
        data.Fractions.Add(null);
        data.Fractions.Add(new MyFrac { N = "3", D = "6" });

        var serializer = new XmlSerializer(typeof(MyData));

        StringBuilder sb = new StringBuilder();

        using (var writer = new StringWriter(sb))
        {
            serializer.Serialize(writer, data);
        }

        // Dump XML
        Console.WriteLine(sb.ToString());
        Trace.WriteLine(sb.ToString());

        using (var reader = new StringReader(sb.ToString()))
        {
            var data2 = (MyData)serializer.Deserialize(reader);
            foreach (var fraction in data2.Fractions)
            {
                var output = fraction == null ? "null" : fraction.ToString();
                Console.WriteLine(output);
                Trace.WriteLine(output);
            }
        }
        Console.ReadLine();
    }
}
公共类MyData
{
公共真菌采集组分;
}
班级计划
{
静态void Main(字符串[]参数)
{
var data=新的MyData();
data.fracts=新的MyCollection();
添加(新的MyFrac{N=“1”,D=“2”});
data.Fractions.Add(空);
data.Fractions.Add(空);
添加(新的MyFrac{N=“3”,D=“6”});
var serializer=newxmlserializer(typeof(MyData));
StringBuilder sb=新的StringBuilder();
使用(var编写器=新的StringWriter(sb))
{
序列化程序。序列化(写入程序、数据);
}
//转储XML
Console.WriteLine(sb.ToString());
Trace.WriteLine(sb.ToString());
使用(var reader=newstringreader(sb.ToString()))
{
var data2=(MyData)序列化程序。反序列化(读取器);
foreach(数据中的var分数2.分数)
{
var output=fraction==null?“null”:fraction.ToString();
控制台写入线(输出);
Trace.WriteLine(输出);
}
}
Console.ReadLine();
}
}
输出xml:

<?xml version="1.0" encoding="utf-16"?>
<MyData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Fractions>
    <MyFrac>1/2</MyFrac>
    <MyFrac xsi:nil="true" />
    <MyFrac xsi:nil="true" />
    <MyFrac>3/6</MyFrac>
  </Fractions>
</MyData>

1/2
3/6
输出数据:

1/2

null

null

3/6


我想这就是你想要的。

空列表元素有意义。所以我需要这些XML文件并还原。是的,谢谢。我希望我忽略了其他一些XmlSerializer属性,我可以应用这些属性来让标准列表序列化程序“做正确的事情”,因为这似乎是一个非常常见的障碍。再次感谢。
public class MyData
{
    public MyCollection<MyFrac> Fractions;
}

class Program
{
    static void Main(string[] args)
    {
        var data = new MyData();
        data.Fractions = new MyCollection<MyFrac>();
        data.Fractions.Add(new MyFrac { N = "1", D = "2" });
        data.Fractions.Add(null);
        data.Fractions.Add(null);
        data.Fractions.Add(new MyFrac { N = "3", D = "6" });

        var serializer = new XmlSerializer(typeof(MyData));

        StringBuilder sb = new StringBuilder();

        using (var writer = new StringWriter(sb))
        {
            serializer.Serialize(writer, data);
        }

        // Dump XML
        Console.WriteLine(sb.ToString());
        Trace.WriteLine(sb.ToString());

        using (var reader = new StringReader(sb.ToString()))
        {
            var data2 = (MyData)serializer.Deserialize(reader);
            foreach (var fraction in data2.Fractions)
            {
                var output = fraction == null ? "null" : fraction.ToString();
                Console.WriteLine(output);
                Trace.WriteLine(output);
            }
        }
        Console.ReadLine();
    }
}
<?xml version="1.0" encoding="utf-16"?>
<MyData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Fractions>
    <MyFrac>1/2</MyFrac>
    <MyFrac xsi:nil="true" />
    <MyFrac xsi:nil="true" />
    <MyFrac>3/6</MyFrac>
  </Fractions>
</MyData>