繁体   English   中英

Xml列表序列化和节点类型名称

[英]Xml List Serialization and Node Type Names

我在这里遇到了多个问题和答案,但都没有针对我的情况。

我有一个带有多个扩展类的“​​实体”类。 我希望序列化能够打入列表,并理解并使用每个项目的类型作为节点名称。

现在,我可以使用注释掉的内容(在主类中定义每个数组项,并通过使用[XmlArrayItem(“ Subclass1”,typeof(subclass1)]]定义其名称,但我想将所有定义保留在其子类中,将有太多的子类来定义主实体类中的所有内容...总有办法实现吗?

我尝试对子类使用[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...
}

创建实体并将Subclass1和Subclass2添加到列表“ CausedBy”类后,序列化上述代码将导致以下结果:

<Entity>
  <CausedBy>
    <Entity ... xsi:type="SubClass1" />
    <Entity ... xsi:type="SubClass2" />
   </CausedBy>
<Entity>

我希望输出显示:

 <Entity>
      <CausedBy>
        <SubClass1 .../>
        <SubClass2 .../>
       </CausedBy>
    <Entity>

由于我完全没有读懂开头的问题,因此这里是一个新答案(有点像tl; dr,因此您始终可以跳到结尾并点击链接):

无法使内置的序列化程序类起作用,因为您不希望添加它需要能够运行的属性。 您唯一的选择是自己上课,但是这不需要听起来那么乏味。 几年前,我在虚拟模式下使用DataGridView遇到了类似的问题,并制作了一个通用虚拟化程序,可用于虚拟化要显示的数据。 它使用了一个自定义属性:

[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;
    }
}

还有一个构造函数:

    ///<summary>
    ///Extracts the properties of the supplied type that are to be displayed
    ///<para>The type must be a class or an InvalidOperationException will be thrown</para>
    ///</summary>
    public Virtualiser(Type t)
    {
        if (!t.IsClass)
            throw new InvalidOperationException("Supplied type is not a class");

        List<VirtualColumnInfo> definedColumns = new List<VirtualColumnInfo>();
        PropertyInfo[] ps = t.GetProperties();
        MethodInfo mg, ms;

        for (int i = 0; i < ps.Length; i++)
        {
            Object[] attr = ps[i].GetCustomAttributes(true);

            if (attr.Length > 0)
            {
                foreach (var a in attr)
                {
                    showColumnAttribute ca = a as showColumnAttribute;
                    if (ca != null)
                    {
                        mg = ps[i].GetGetMethod();
                        if (mg != null)
                        {
                            ms = ps[i].GetSetMethod();
                            definedColumns.Add
                            (
                                new VirtualColumnInfo
                                (
                                    ps[i].Name, ca.Width, ca.ReadOnly, ca.Title == String.Empty ? ps[i].Name : ca.Title, 
                                    ca.Format, mg, ms
                                )
                            );
                        }
                        break;
                    }
                }
            }
        }
        if (definedColumns.Count > 0)
            columns = definedColumns.ToArray();
    }

这将提取类的公共属性,并将带有标记的项目作为列以及标题,格式等提供给DataGridView。

所有这些(以及其余缺少的代码)的结果是,只需标记公共属性并为给定类型调用一次虚拟器,就可以在dataGridView中将任何类型虚拟化:

    #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

这将虚拟化dataGridView的任何类以显示和编辑数据,并且我多年来使用了很多次,提取属性以显示的正是XML序列化所必需的,实际上,它具有许多相同的特性。

我打算改用这种方法来完成XML序列化的相同工作,但是有人已经在https://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=474453上做到了,希望您可以使用解决您的问题的方法。

这对我有用:

    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 { } }
}

它产生:

<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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM