title: How to use SGen to generate a serialization assembly for a XML schema that is mapped to a two-level array?
body: <p>I'm consuming a third-party service that requires XmlSerializerFormat contracts; I want to speed up startup by creating a serialization assembly, but Sgen.exe really doesn't like a particular construct in the schema that Xsd.exe spits out a nested array for.</p>
  
  <p>The schema includes sequences of elements nested two levels deep like so:</p>
  
  <h3><code>Foo.xsd</code></h3>
  
  <pre class="lang-xml prettyprint-override"><code>&lt;xs:schema targetNamespace="http://example.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com" elementFormDefault="qualified"&gt;
      &lt;xs:element name="Foo" type="Foo"/&gt;
      &lt;xs:complexType name="Foo"&gt;
          &lt;xs:sequence&gt;
              &lt;xs:element name="List" type="FooList" minOccurs="0" maxOccurs="unbounded"/&gt;
          &lt;/xs:sequence&gt;
      &lt;/xs:complexType&gt;
      &lt;xs:complexType name="FooList"&gt;
          &lt;xs:sequence&gt;
              &lt;xs:element name="Item" type="FooListItem" minOccurs="0" maxOccurs="unbounded"/&gt;
          &lt;/xs:sequence&gt;
      &lt;/xs:complexType&gt;
      &lt;xs:complexType name="FooListItem"&gt;
          &lt;xs:simpleContent&gt;
              &lt;xs:extension base="xs:string"/&gt;
          &lt;/xs:simpleContent&gt;
      &lt;/xs:complexType&gt;
  &lt;/xs:schema&gt;
  </code></pre>
  
  <p>That is: a toplevel <code>Foo</code> contains many <code>FooList</code>s, and a <code>FooList</code> contains many <code>FooListItem</code>.</p>
  
  <p>Running <code>xsd /c Foo.xsd</code> produces the following:</p>
  
  <h3><code>Foo.cs</code></h3>
  
  <pre class="lang-cs prettyprint-override"><code>using System.Xml.Serialization;
  
  [XmlType(Namespace="http://example.com")]
  [XmlRoot(Namespace="http://example.com", IsNullable=false)]
  public partial class Foo {
  
      private FooListItem[][] listField;
  
      [XmlArrayItem("Item", typeof(FooListItem), IsNullable=false)]
      public FooListItem[][] List {
          get {
              return this.listField;
          }
          set {
              this.listField = value;
          }
      }
  }
  
  [XmlType(Namespace="http://example.com")]
  public partial class FooListItem {
  
      private string valueField;
  
      [XmlText]
      public string Value {
          get {
              return this.valueField;
          }
          set {
              this.valueField = value;
          }
      }
  }
  </code></pre>
  
  <p>That is, no class for <code>FooList</code> is present for some reason, instead there's just a nested array of <code>FooListItem</code>s.</p>
  
  <p>However, when I build this and run Sgen.exe on the resulting DLL using just <code>sgen /keep obj\Debug\net461\Foo.dll</code>, this chokes on the following error messages:</p>
  
  <blockquote>
    <p>error CS0030: Cannot convert type 'FooListItem[]' to 'FooListItem'<br>
    error CS0029: Cannot implicitly convert type 'FooListItem' to 'FooListItem[]'  </p>
  </blockquote>
  
  <p>(I'm using .NET 4.7 versions of Xsd.exe and Sgen.exe, I'm just targeting 4.6.1 for compatibility.)</p>
  
  <p>Looking at the generated code, it chokes in the following method:</p>
  
  <pre class="lang-cs prettyprint-override"><code>void Write3_Foo(string n, string ns, global::Foo o, bool isNullable, bool needType) {
      if ((object)o == null) {
          if (isNullable) WriteNullTagLiteral(n, ns);
          return;
      }
      if (!needType) {
          System.Type t = o.GetType();
          if (t == typeof(global::Foo)) {
          }
          else {
              throw CreateUnknownTypeException(o);
          }
      }
      WriteStartElement(n, ns, o, false, null);
      if (needType) WriteXsiType(@"Foo", @"http://example.com");
      {
          // THIS SEEMS TO BE THE ROOT CAUSE
          global::FooListItem[][] a = (global::FooListItem[][])((global::FooListItem[][])o.@List);
          if (a != null){
              WriteStartElement(@"List", @"http://example.com", null, false);
              for (int ia = 0; ia &lt; a.Length; ia++) {
                  // ERROR IS REPORTED HERE
                  Write2_FooListItem(@"Item", @"http://example.com", ((global::FooListItem)a[ia]), false, false);
              }
              WriteEndElement();
          }
      }
      WriteEndElement(o);
  }
  </code></pre>
  
  <p>So it seems like Xsd.exe and Sgen.exe try to realize the pattern where an element has an explicit "list of X" child containing X items without creating a separate class for the list element, but only relying on the name of the serialized property to synthetise the intermediate element; and this breaks when the list element itself may be repeated.</p>
  
  <p><strong>Is there a way to work around this?</strong> Like force Xsd.exe to generate a class for the intermediate element? I suppose this might be an actual bug in Xsd.exe and Sgen.exe, but that won't really help me in a reasonable time frame.</p>
  
  <hr>
  
  <p>As said above, this is a third-party service; I have absolutely no control over the schema and the less manual editing of generated code involved the better since my actual files are tens of thousands of lines long.</p>