C# Xml列表序列化和节点类型名称
我在这里遇到了很多问题和答案,但没有一个是针对我的情况的 我有一个类“实体”,其中有多个扩展的类。我希望序列化能够命中列表,理解并使用每个项的类型作为节点名 现在,我可以使用注释掉的内容(定义主类中的每个数组项,并使用[XmlArrayItem(“subclass 1”,typeof(subclass 1)]定义这些项的名称),但我想将所有定义保留在它们的子类中,我将有太多的子类来定义主实体类中的所有内容……是否有办法实现这一点 我曾尝试对子类等使用[XmlType(TypeName=“…”),但没有成功C# Xml列表序列化和节点类型名称,c#,xml,serialization,xsi,C#,Xml,Serialization,Xsi,我在这里遇到了很多问题和答案,但没有一个是针对我的情况的 我有一个类“实体”,其中有多个扩展的类。我希望序列化能够命中列表,理解并使用每个项的类型作为节点名 现在,我可以使用注释掉的内容(定义主类中的每个数组项,并使用[XmlArrayItem(“subclass 1”,typeof(subclass 1)]定义这些项的名称),但我想将所有定义保留在它们的子类中,我将有太多的子类来定义主实体类中的所有内容……是否有办法实现这一点 我曾尝试对子类等使用[XmlType(TypeName=“…”),
[Serializable]
[XmlInclude(typeof(Subclass1))]
[XmlRoot("Entity")]
public class Entity{
[XmlArray("CausedBy")]
//[XmlArrayItem("Subclass1", typeof(subclass1))]
//[XmlArrayItem("Sublcass2", typeof(Subclass2))]
public List<Entity> CausedBy { get; set; }
}
[Serializable]
[XmlRoot("Subclass1")]
[XmlInclude(typeof(Subclass2))]
public class Subclass1:Entity{
//Code...
}
[Serializable]
[XmlRoot("Subclass2")]
public class Subclass2:Subclass1{
//Code...
}
[可序列化]
[xmlclude(类型(子类1))]
[XmlRoot(“实体”)]
公共类实体{
[XmlArray(“原因”)]
//[XmlArrayItem(“子类1”,类型(子类1))]
//[XmlArrayItem(“子类2”,类型(子类2))]
由{get;set;}引起的公共列表
}
[可序列化]
[XmlRoot(“第1子类”)]
[xmlclude(类型(第2子类))]
公共类子类1:实体{
//代码。。。
}
[可序列化]
[XmlRoot(“第2子类”)]
公共类子类2:子类1{
//代码。。。
}
在创建实体并将子类1和子类2添加到列表“CausedBy”类后序列化上述代码会导致以下结果:
<Entity>
<CausedBy>
<Entity ... xsi:type="SubClass1" />
<Entity ... xsi:type="SubClass2" />
</CausedBy>
<Entity>
我希望输出显示:
<Entity>
<CausedBy>
<SubClass1 .../>
<SubClass2 .../>
</CausedBy>
<Entity>
这对我很有用:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Entity entity = new Entity();
entity.CausedBy = new List<Entity>();
entity.CausedBy.Add(new Subclass1());
entity.CausedBy.Add(new Subclass2());
entity.CausedBy.Add(new Subclass2());
entity.CausedBy.Add(new Subclass1());
entity.CausedBy.Add(new Subclass1());
entity.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Test.txt"));
}
}
[Serializable]
[XmlRoot("Entity")]
public class Entity
{
[XmlArray("CausedBy")]
[XmlArrayItem("SubClass1", typeof(Subclass1))]
[XmlArrayItem("SubClass2", typeof(Subclass2))]
public List<Entity> CausedBy { get; set; }
}
[Serializable]
[XmlRoot("Subclass1")]
public class Subclass1 : Entity
{
[XmlIgnore]
String t = DateTime.Now.ToShortDateString();
public String SubClass1Item { get { return "Test1 " + t; } set { } }
}
[Serializable]
[XmlRoot("Subclass2")]
public class Subclass2 : Entity
{
[XmlIgnore]
String t = DateTime.Now.ToString();
public String SubClass2Item { get { return "Test2 " + t; } set { } }
}
public Form1()
{
初始化组件();
}
私有void Form1\u加载(对象发送方、事件参数e)
{
实体=新实体();
entity.CausedBy=新列表();
entity.CausedBy.Add(新的子类1());
entity.CausedBy.Add(新的子类2());
entity.CausedBy.Add(新的子类2());
entity.CausedBy.Add(新的子类1());
entity.CausedBy.Add(新的子类1());
保存(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),“Test.txt”);
}
}
[可序列化]
[XmlRoot(“实体”)]
公共类实体
{
[XmlArray(“原因”)]
[XmlArrayItem(“子类1”,类型(子类1))]
[XmlArrayItem(“第2子类”,类型(第2子类))]
由{get;set;}引起的公共列表
}
[可序列化]
[XmlRoot(“第1子类”)]
公共类子类1:实体
{
[XmlIgnore]
String t=DateTime.Now.ToShortDateString();
公共字符串子类1项{get{return“Test1”+t;}set{}
}
[可序列化]
[XmlRoot(“第2子类”)]
公共类子类2:实体
{
[XmlIgnore]
字符串t=DateTime.Now.ToString();
公共字符串子类2项{get{return“Test2”+t;}set{}
}
它产生:
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CausedBy>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
<SubClass2>
<SubClass2Item>Test2 20/09/2017 01:06:55</SubClass2Item>
</SubClass2>
<SubClass2>
<SubClass2Item>Test2 20/09/2017 01:06:55</SubClass2Item>
</SubClass2>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
</CausedBy>
</Entity>
测试1 2017年9月20日
Test2 20/09/2017 01:06:55
Test2 20/09/2017 01:06:55
测试1 2017年9月20日
测试1 2017年9月20日
因为太长了,读不下去了,所以我有一个新的答案(这有点太大了,DR,所以你可以跳过到最后,然后跟着链接):< /P>
不可能让内置序列化器类正常工作,因为您不希望添加它需要能够操作的属性。您唯一的选择是自己序列化该类,但是,这不必像听起来那么乏味;几年前,我在虚拟模式下使用DataGridView时遇到了类似的问题,并生成了一个通用virtualizer,可用于虚拟化数据以进行显示;它使用了一个自定义属性:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class showColumnAttribute : System.Attribute
{
///<summary>Optional display format for column</summary>
public string Format;
///<summary>Optional Header string for column<para>Defaults to propety name</para></summary>
public string Title;
///<summary>Optional column edit flag - defaults to false</summary>
public bool ReadOnly;
///<summary>Optional column width</summary>
public int Width;
///<summary>
///Marks public properties that are to be displayed in columns
///</summary>
public showColumnAttribute()
{
Format = String.Empty;
Title = String.Empty;
ReadOnly = false;
Width = 0;
}
}
通过创建从类数据派生的许多公共属性,可以自动指定列数、列的属性和顺序:
#region Display columns
[showColumn(ReadOnly = true, Width = 100, Title = "Identification")]
public String DisplayIdent
{
get
{
return ident;
}
set
{
ident = value;
}
}
[showColumn(Width = 70, Title = "Number on Roll")]
public int DisplayNumber
{
get
{
return number;
}
set
{
number = value;
}
}
[showColumn(Width = -100, Title = "Name")]
public string DisplayName
{
get
{
return name == String.Empty ? "??" : name;
}
set
{
name = value;
}
}
#endregion
这将虚拟化dataGridView的任何类以显示和编辑数据,多年来我多次使用它,提取要显示的属性正是XML序列化所需要的,事实上,它具有许多相同的特性
我本来打算调整这个方法来做同样的XML序列化工作,但有人已经在做了,我希望你能利用这个方法来解决你的问题。1,子类2是从子类12扩展而来的,是的,我知道我可以通过在实体类中定义类型来定义数组项(我已经把它放在问题中了)问题是,我将有很多子类,不想在“实体”类中定义所有子类。我希望它根据属性或类型或其他内容自动执行。对不起,输入错误。输出是相同的,除了记录的内容:Test1 20/09/2017 Test2 20/09/2017 01:25:34您仍在定义arr实体类中的ay项和类型名称。这是我不想要的。我在原始版本中已经注释掉了。我想要一种在子类Themselves中定义这些内容的方法抱歉-我真的不应该在早些时候看这些东西…我将再看一看。检查这个问题,我认为你不可能想要什么。列表由必须有一些属性,否则XmlSerializer根本无法工作。我会继续挖掘,但它们是序列化程序的提示,我知道没有办法将这些信息延迟到派生类。
#region Virtualisation
static readonly Virtualiser Virtual = new Virtualiser(typeof(UserRecord));
[XmlIgnore] // just in case!
public static int ColumnCount { get { return Virtual.ColumnCount; } }
public static VirtualColumnInfo ColumnInfo(int column)
{
return Virtual.ColumnInfo(column);
}
public Object GetItem(int column)
{
return Virtual.GetItem(column, this);
}
/*
** The supplied item should be a string - it is up to this method to supply a valid value to the property
** setter (this is the simplest place to determine what this is and how it can be derived from a string).
*/
public void SetItem(int column, Object item)
{
String v = item as String;
int t = 0;
if (v == null)
return;
switch (Virtual.GetColumnPropertyName(column))
{
case "DisplayNumber":
if (!int.TryParse(v, out t))
t = 0;
item = t;
break;
}
try
{
Virtual.SetItem(column, this, item);
}
catch { }
}
#endregion
#region Display columns
[showColumn(ReadOnly = true, Width = 100, Title = "Identification")]
public String DisplayIdent
{
get
{
return ident;
}
set
{
ident = value;
}
}
[showColumn(Width = 70, Title = "Number on Roll")]
public int DisplayNumber
{
get
{
return number;
}
set
{
number = value;
}
}
[showColumn(Width = -100, Title = "Name")]
public string DisplayName
{
get
{
return name == String.Empty ? "??" : name;
}
set
{
name = value;
}
}
#endregion