title: How to group properties into a sub-object when serializing to JSON
body: <p>Given this class:</p>
  
  <pre><code>public class Thing
  {
      public string Alpha { get; set; }
      public string Beta { get; set; }            
  }
  </code></pre>
  
  <p>I need to serialize arbitrary subclasses of Thing which subclasses may themselves add Thing properties.  For example...</p>
  
  <pre><code>public class SomeThing : Thing
  {
    public string Delta {get; set; }
  
    public Thing ThisThing { get; set; }
    public Thing ThatThing { get; set; }
  }
  </code></pre>
  
  <p>It is easy, using Newtonsoft Json.NET to serialize a SomeThing class to this:</p>
  
  <pre><code>{
    alpha: "x",
    beta: "x",
    delta: "x",
  
    thisThing: {
      alpha: "y",
      beta: "y"
    },
    thatThing: {
      alpha: "z",
      beta: "z"
    }
  }
  </code></pre>
  
  <p>What I <em>want</em> to do, though, is this (<em>without</em> changing the Thing or SomeThing classes):</p>
  
  <pre><code>{
    alpha: "x",
    beta: "x",
    delta: "x",
  
    things: {
      thisThing: {
        alpha: "y",
        beta: "y"
      },
      thatThing: {
        alpha: "z",
        beta: "z"
    }  
  }
  </code></pre>
  
  <p>That is, I want to collect any Thing properties into a sub-object named <strong>things</strong>.</p>
  
  <p>Another example:</p>
  
  <pre><code>public class SomeThingElse : Thing
  {
    public int Gamma {get; set; }
  
    public Thing Epsilon { get; set; }
  }
  </code></pre>
  
  <p>...would serialize to</p>
  
  <pre><code>{
    alpha: "x",
    beta: "x",
    gamma: 42,
  
    things: {
      epsilon: {
        alpha: "y",
        beta: "y"
      }
    }
  }
  </code></pre>
  
  <p>By creating a contract resolver I can easily peel out the individual thing properties and leave the non-things to serialize themselves.  But I don't know how to create the things property and stuff back in the properties I peeled out:</p>
  
  <pre><code>public class MyContractResolver : CamelCasePropertyNamesContractResolver
  {
      protected override IList&lt;JsonProperty&gt; CreateProperties(Type type, MemberSerialization memberSerialization)
      {
          var properties = base.CreateProperties(type, memberSerialization);
  
          // grab the properties that are NOT a Thing
          var toCreate = properties.Where(p =&gt; !typeof(Thing).IsAssignableFrom(p.PropertyType)).ToList();
  
          // grab the properties that ARE a Thing            
          var toGroup = properties.Where(p =&gt; typeof(Thing).IsAssignableFrom(p.PropertyType)).ToList();
  
          // create the new things property to stuff toGroup into
          var things = new JsonProperty
          {
              PropertyName = "things"
          };
  
          // THIS IS WHERE I'M STUCK...
          // TODO: somehow stuff toGroup into "things"
  
          // put the group back along with the non-thing properties
          toCreate.Add(things);
  
          // return the re-combined set of properties
          return toCreate;
      }            
  }
  </code></pre>
  
  <p>I use this resolver as follows (simplified for this question):</p>
  
  <pre><code>static void Main(string[] args)
  {
      var st = new SomeThing
      {
          Alpha = "x",
          Beta = "x",
          Delta = "x",
          ThisThing = new Thing() {Alpha = "y", Beta = "y"},
          ThatThing = new Thing() {Alpha = "z", Beta = "z"}
      };
  
      var settings = new JsonSerializerSettings
      {
          ContractResolver = new MyContractResolver(),
          Formatting = Formatting.Indented
      };
  
      var result = JsonConvert.SerializeObject(st, settings);
  
      Console.WriteLine(result);
  }
  </code></pre>
  
  <p>Which produces</p>
  
  <pre><code>{
    alpha: "x",
    beta: "x",
    delta: "x"
  }
  </code></pre>
  
  <p>Notice that even though I've created and added a JsonProperty with the name of "things" it does not appear.  My hope is I just need to fill in the blanks near the TODO in the contract resolver.  </p>
  
  <p>Or maybe I'm going in the wrong direction.  Can you help me?</p>