2017-09-19 7 views
0

ここでは複数の質問と回答が出てきますが、私の状況には特に関係しません。Xmlリストのシリアライゼーションとノードタイプの名前

私はクラス「Entity」に複数のクラスがあります。シリアライゼーションがリストにヒットして、ノード名の各項目のタイプを理解して使用したいと思います。

ここでは、コメントアウトされたものを使用できます(メインクラスの各配列項目を定義し、[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を追加した後に上記のコードをシリアル化以下でDBY」クラスの結果:

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

私は出力を表示したいと思い:

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

答えて

1

私は全く読まなかったので最初に質問してください、ここに新しい答えがあります(これはちょっとしたことですので、最後までスキップしてリンクに従うことができます):

組み込みシリアライザクラスを取得することはできませんあなたが動作するために必要な属性を追加したくないからです。あなたの唯一の選択肢は、自分自身でクラスをセロライズすることですが、これは聞こえるほど退屈である必要はありません。数年前に仮想モードの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にアイテムをマークし、それは、カスタム属性を使用しました

このすべて(および欠けているコードの残りの部分)の効果は、パブリックプロパティにタグを付けるだけで、特定のタイプの仮想化ツールを呼び出すことで、どのタイプもデータグリッドビューで仮想化できるということでした。

#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でそれを行っています。この方法を使って問題を解決できることを願っています。

0

これは私の作品:

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

1、サブクラス2はサブクラス1から拡張されます 2、はい私は、エンティティクラスの型を定義することで配列アイテムを定義できます(私は質問に入れました)ことは、私はサブクラス'エンティティ'クラスですべてを定義する必要はありません。属性やタイプなどに基づいて自動的にそれを行うようにしたい –

+0

残念ながら、出力はレコードの内容を除いて同じです: Test1 20/09/2017 < SubClass2Item> Test2 20/09/2017 01:25:34

+0

あなたは依然として配列項目と型名をエンティティクラスに定義しています。それは私が望まないものです。私はそれがすでに元のコメントになっています。私はそのようなサブクラス自体で定義する方法をしたい –

関連する問題