JavaScript Object Notation (JSON) is a subset of the JavaScript language used for the definition and exchange of data. While I’m not proposing that we create a similar standard using C#, I do want to illustrate some of the rich object initialization syntax of the language. This terse syntax can come in handy when defining data for things like unit tests, templating models, etc.

Object Initializers

Consider the following class.

class Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

Object initializers allow you to create a new object and set its properties in the same statement. Here is an example.

var x = new Point { X = 0, Y = 1 };

This syntax can be nested and and shortened by allocating instances inside constructors. Consider the following class.

class Rectangle
{
    public Point P1 { get; } = new Point();
    public Point P2 { get; } = new Point();
}

It can be initialized as follows.

var x = new Rectangle
{
    P1 = { X = 0, Y = 1 },
    P2 = { X = 2, Y = 3 }
};

Collection Initializers

Collection initializers let you create and add items to a collection in the same statement. The class must implement IEnumerable and have a method named Add. C# 6 even allows the Add method to be an extension method. Consider the following “class”. (I know it won’t actually compile.)

class IntCollection : IEnumerable
{
    public void Add(int value) { }
}

It can be initialized using the following syntax.

var x = new IntCollection { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

The Add method can have multiple parameters…

class LineString : IEnumerable
{
    public void Add(int x, int y) { }
}

…and be initialized like this.

var x = new LineString { { 0, 1 }, { 2 , 3 }, { 4 , 5 } };

The Add method can even be overloaded!

class StringAndIntCollection : IEnumerable
{
    public void Add(string value) { }
    public void Add(int value) { }
}
var x = new StringAndIntCollection { 0, "1", 2, "3" };

Collection initializers can also be nested and shortened inside object initializers.

class Contact
{
    public string Name { get; set; }
    public List<string> PhoneNumbers { get; } = new List<string>();
}
var x = new Contact
{
    Name = "Chris Smith",
    PhoneNumbers = { "206-555-0101", "425-882-8080" }
};

The only downfall of collection initializers is that they can’t be used with object initializers on the same instance.

class NamedIntCollection : IEnumerable
{
    public string Name { get; set; }
    public void Add(int value) { }
}
// Like this...
var x = new NamedIntCollection { Name = "Primes" };
x.Add(2);
x.Add(3);
x.Add(5);

// ...or this...
var y = new NamedIntCollection { 2, 3, 5 };
x. Name = "Primes";

// ...but NEVER this.
var z = new NamedIntCollection { Name = "Primes", 2, 3, 5 };

Index Initializers

Index initializers are new to C# 6. In order to use them, an indexer must be present.

class IntToStringMap
{
    public string this[int index] { get; set; }
}

Their syntax is pretty intuitive.

var x = new IntToStringMap
{
    [7] = "seven",
    [9] = "nine",
    [13] = "thirteen"
};

The indexer can have multiple parameters.

class Bitmap
{
    public bool this[int x, int y] { get; set; }
}
var x = new Bitmap
{
    [0, 0] = true,
    [0, 1] = false,
    [1, 0] = false,
    [1, 1] = true
};

It can be overloaded too.

class IntToStringAndBackMap
{
    public string this[int index] { get; set; }
    public int this[string index] { get; set; }
}
var x = new IntToStringAndBackMap
{
    [0] = "zero",
    ["one"] = 1
};

The syntax can also be shortened by instantiating objects inside the getter.

class ScatterPlot
{
    public Point this[int index]
    {
        get { return new Point(); }
        set { }
    }
}
var x = new ScatterPlot
{
    [0] = { X = 0, Y = 1},
    [1] = { X = 2, Y = 3}
};

Indexer initializers, unlike collection initializers, can be mixed with object initializers.

class NamedMap
{
    public string Name { get; set; }
    public string this[string index] { get; set; }
}
var x = new NamedMap
{
    Name = "Atbash Cipher",
    ["A"] = "Z",
    ["B"] = "Y",
    ["C"] = "X"
};

Pop Quiz

Alright, it’s time to put everything you’ve learned to the test. Can you come up with a class that enables the following syntax? :wink:

var x = new Thing
{
    A = 1,
    ["B"] = 2,
    ["C", 3] = { "D", { 4, "E" } },
    [5] = { F = 6 }
};

Conclusion

If we were to come up with a standard, I’m not sure what we’d call it since the obvious, CSON, is already taken by CoffeeScript. The following, however, is an example of a theoretical C# Object Notation document that could be used to create a SQL script.

new Schema
{
    new Table
    {
        Name = "Customer",
        ["Id"] = { Type = "int", Required = true },
        ["Name"] = { Type = "varchar(30)" },
        Constraints =
        {
            new PrimaryKey { Name = "PK_Customer", Columns = { "Id" } }
        }
    },
    new Table
    {
        Name = "Order",
        ["Id"] = { Type = "int", Required = true },
        ["CustomerId"] = { Type = "int", Required = true },
        ["Total"] = { Type = "real" },
        Constraints =
        {
            new PrimaryKey { Name = "PK_Order", Columns = { "Id" } },
            new ForeignKey
            {
                Name = "FK_Order_Customer",
                Columns = { "CustomerId" },
                ReferencedTable = "Customer",
                ReferencedColumns = { "Id" }
            }
        }
    }
}