HowTo: Fluent Interfaces – schöne APIs mit C# 3.0

APIs (egal ob sie nur für interne Zwecke da sind oder auch an externe Entwicklern geht) sollten möglichst einfach und intuitiv zu bedienen sein.
Seit kurzem lese ich immer häufiger von “Fluent Interfaces“.

Was ist das denn?
Schauen wir uns einfach mal das Wikipedia Beispiel an:

public class ExampleProgram
    {
        [STAThread]
        public static void Main(string[] args)
        {
            //Standard Example
            IConfiguration config = new Configuration();
            config.SetColor("blue");
            config.SetHeight(1);
            config.SetLength(2);
            config.SetDepth(3);
            //FluentExample
            IConfigurationFluent config =
                  new ConfigurationFluent().SetColor("blue")
                                           .SetHeight(1)
                                           .SetLength(2)
                                           .SetDepth(3);
        }

Anstatt nur einzelne Methodenaufrufe zu haben, ist es doch viel angenehmer diese in “einem Satz” niederzuschreiben. Diese Technik findet auch in diversen Javascript-Bibliotheken Einsatz (z.b: jQuery)

Sieht nicht schlecht aus – wie macht man sowas?
Es gibt (wie in dem Wikipedia Beispiel) sicherlich ein paar Tricks wie man sowas machen kann – durch Rob Conerys Storefront Projekt bin ich konkret auf das “Pipes and Filters” Pattern gekommen.

Die Idee (in der Rob Conery Version ;) )
Wir haben einen großen Datenhaufen (unser Repository), wo wir über Filter bestimmte Sachen einfach uns abzapfen können, wie wir es brauchen.

image 

Das tolle nun daran: Man kann nicht nur ein Filter nehmen, sondern kann diese auch zusammenschließen um seine Ergebnisse noch weiter einzuengen:

image

Rob Conery hat dies auch in einem Screencast recht gut erklärt.

Die Umsetzung in .NET mit C# 3.0:
Als “Daten” haben wir in unserem Beispiel einfach eine simple Person Klasse:

    public class Person
    {
        public int Age { get; set; }
        public string Name { get; set; }
    }

Der Aufbau ist ähnlich empfunden wie bei diesem Blogpost – allerdings etwas vereinfacht (und sollte so nicht verwendet werden (Schnittstellen einbauen!))

Unser DummyPersonRepository hat nur eine Methode, welche statisch ein paar Objekte erzeugt:

    public class DummyPersonRepository
    {
        public IQueryable<Person> GetPersons()
        {
            List<Person> returnValues = new List<Person>()
                {
                    new Person() { Age = 11, Name = "Bob" },
                    new Person() { Age = 22, Name = "Alice" },
                    new Person() { Age = 20, Name = "Robert" },
                    new Person() { Age = 40, Name = "Hans" },
                    new Person() { Age = 20, Name = "Peter" },
                    new Person() { Age = 20, Name = "Oli" },
                };

            return returnValues.AsQueryable();
        }
    }

Nun kommen unsere Filter ins Spiel – die nicht direkt ins Repository kommen! Diese werden über “Extension Methods” in einer seperaten Klasse implementiert:

    public static class PersonFilters
    {
        public static IQueryable<Person> WithAge(this IQueryable<Person> qry, int age)
        {
            return (from x in qry
                    where x.Age == age
                    select x);
        }

        public static IQueryable<Person> NameStartsWith(this IQueryable<Person> qry, string start)
        {
            return (from x in qry
                    where x.Name.StartsWith(start)
                    select x);
        }
    }

Hier fragen wir einmal nach dem Alter und ob der Name mit was bestimmten beginnt – beides als “Extension Method”.

In unserem Service können wir nun so eine Methode bereitstellen:

        public IList<Person> GetPersons(int age, string startsWith)
        {
            return this.PersonRep.GetPersons().WithAge(age).NameStartsWith(startsWith).ToList();
        }

Sehr einfach und effektiv :)

Ergebnis:
Am Ende können wir einfach in einer Konsolenapplikation sowas aufrufen:

static void Main(string[] args)
        {
            PersonService srv = new PersonService();
            List<Person> resultList = srv.GetPersons(20, "R").ToList();
            foreach (Person result in resultList)
            {
                Console.WriteLine("Name {0} - Age {1}", result.Name, result.Age);
            }

            Console.Read();
        }

Die Projektstruktur:

image

Natürlich ist das nur ein simples Beispiel, allerdings konnte ich dies bereits effektiv in einem Projekt einsetzen.

Neben Rob Conerys Storefront kann man sich auch diesen Democode von Mike Bosch anschauen (Teil 1 & 2) – auch er findet diese Idee sehr cool :)

Insgesamt erlaubt ein solcher Programmierstil deutlich schickeren Code – wie bereits das Wikipedia Beispiel am Anfang gezeigt haben sollte.

[ Download Democode ]

HowTo: Generische Extensions

C# 3.0 bringt ein nettes Feature mit: Extensions.

Generell sind die recht einfach, allerdings sind die meisten Beispiele ohne Generics gemacht.

Meine Problemsituation:
In einem Projekt waren einige Klasse von List<…> abgeleitet:

    public class MyList : List<MyObject>
    {
        ...
    }

Jede dieser “Listenklassen” hatte eine kleine Methode, welche diese Liste durchgeht und eine Aktion auslöst.

Ganz nach dem Prinzip: Keep it DRY
Don´t repeat yourself – daher müssen diese eigentlich gleichen Methoden weg und in eine Extension Methode. Da der Syntax von den generischen Extensions mir etwas Zeit geraubt hat, stell ich ihn mal der Allgemeinheit offen.

In unserem Beispiel:
Wir wollen eine kleine Extension schreiben, welche mehrere Elemente an eine ICollection anfügt – kann man auch über AddRange lösen, aber z.B. hat die ObservableCollection das nicht – daher nehmen wir einfach mal dieses Beispiel.

Source Code:
Main:

class Program
    {
        static void Main(string[] args)
        {
            List<int> intList = new List<int>();
            intList.Add(1);
            intList.Add(2);
            intList.Add(3);

            List<int> newIntList = new List<int>();
            newIntList.Add(4);
            newIntList.Add(5);

            intList.Add(newIntList);

            foreach (int myInt in intList)
            {
                Console.WriteLine(myInt); // Should be 1,2,3,4,5
            }

            Console.ReadLine();
        }
    }

Extension:

    public static class Extensions
    {
        public static ICollection<T> Add<T>(this ICollection<T> src, ICollection<T> addingElements)
        {
            foreach (T element in addingElements)
            {
                src.Add(element);
            }
            return src;
        }
    }

Resultat: Viele Ts und eine kleine generische Extension.

[ Download Source Code ]

Buchüberblick Januar 2008 – .NET 3.5, ASP.NET 3.5, AJAX, ADO.NET, LINQ

Das .NET Framework in der Version 3.5 ist schon eine Weile draußen und da ich selber immer auf der Suche nach aktuellen Büchern bin, hier eine aktuelle Auswahl oder kommenden Büchern – Haupthema ist ASP.NET 3.5, .NET 3.5, AJAX oder LINQ.

Deutschsprachige:

Englischsprachige:

Das ganze natürlich noch als schickes Widget ;)

HowTo: O/R Mapper LINQ to SQL – Einführung & einfaches manuelles Mapping

LINQ to SQL ist Microsofts LINQ Provider für das Hauseigene Datenbanksystem SQL Server 2005 (und 2008 – und noch mehr?). Das Konzept von LINQ sollte man vorher bereits verstehen – hier eine Kurzeinführung:

LINQ? Was ist das?

In jeder Applikation arbeitet man mit Daten, Objekten und noch mehr Ansammlungen von Objekten. Externe Datenquellen (XML, Datenbanken) muss man über ihre jeweiligen Abfragesprachen ansprechen – SQL oder XPath. Objektcollections oder komplexe Objekte in C# 2.0 haben kein solches Abfragesystem gehabt – man musste über Foreach-Schleifen die Collections durchgehen und dann immer wieder mit dem Suchwort vergleichen.

Hier tritt LINQ ins Spiel – LINQ erlaubt es, .NET Objekte mit einem SQL ähnlichen Syntax zu durchsuchen, allerdings mit allen Vorteilen die Visual Studio und Objekte bieten: Einfaches Debugging möglich, man arbeitet mit direkten Objekten und die IntelliSense hilft natürlich auch kräftig. Am Ende einer LINQ Abfrage kann man direkt ein “var” Objekt erzeugen (was das ist, wurde hier besprochen). Da man nicht nur Objekte so durchsuchen kann, sondern auch andere Daten, zeigt z.B. der LINQ to XML oder der LINQ to SQL Provider.

Microsoft hat LINQ so gestaltet, dass viele solche Provider erstellt werden können, sodass es momentan z.B. folgene Provider in Entwicklung befinden:

Wir beschäftigen uns heute mit LINQ to SQL – dabei werden wir einmal nur in einer sehr einfachen Abfrage LINQ to SQL anschauen und später ein etwas komplexeres Mapping per Hand vornehmen.
Der LINQ to SQL Designer wird später behandelt!

Vorbereitung & Dokumente

Ich halte mich hier an das Hand on Lab von Microsoft, welches es hier kostenlos zum Runterladen gibt. Desweiteren benötigen wir die Northwind Datenbank – eine Installationsanleitung gibt es hier. Natürlich benötigen wir Visual Studio 2008 Express Edition. Visual Studio und das SQL Management Studio sollten im Administratormodus laufen (und bei meinem Demoprojekt muss hinterher der ConnectionString angepasst werden)

Erster Schritt mit LINQ to SQL

Als erstes benötigen wir die System.Data.Linq.dll, damit wir die entsprechenden Namespaces verwenden können.
Danach erstellen wir unser erstes Mapping (wie bereits oben erwähnt, werden wir hier ein manuelles Mapping vornehmen um das System besser zu verstehen).

Schauen wir uns mal die Tabellen der Northwind Datenbank an:

image

Wir wollen einfach eine kleine Konsolen-Applikation haben, welche die Kundendaten bearbeitet.

LINQ to SQL – Schritt 1: Das Mapping

Die Kundendaten stehen in der “Customers” Tabelle – daher legen wir eine “Customers” Klasse an:

image

Dabei verwenden wir den Namespace “System.Data.Linq.Mapping” in der “Customer.cs”.
Das Mapping erfolgt über das Zuweisen von Attributen zu der Klasse (das Table Attribut) und den Properties (das Column Attribut).

Quellcode sagt meist mehr als tausend Wort:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq.Mapping;

namespace LinqToSqlTest
{
    [Table(Name = "Customers")]
    public class Customer
    {
        [Column(IsPrimaryKey = true)]
        public string CustomerID;

        [Column]
        public string Address { get; set; }

        private string _City;

        [Column(Storage = "_City")]
        public string City
        {
            get { return this._City; }
            set { this._City = value; }
        }
    }

}

Erklärung:

Das Mapping erfolgt durch die Zuweisungen der entsprechenen Attribute (Attribute-based Mapping) – beim Klassennamen “Customer” wird das Tabel Attribut verwendet – das “Name” dort verbindet die “Costumers” Tabelle mit dieser Klasse. Der Name kann auch weggelassen werden, wenn DB Tabellennamen == Klassenname (in unserem Fall fehlt ein “s” im Klassennamen).
Die einzelnen Spalten werden über das Column Attribut den Properties zugewiesen (MSDN Artikel: How to: Represent Columns as Class Members (LINQ to SQL)).

Das Mapping erfolgt hierbei wieder anhand des Namens der DB Spalte und des entsprechenden Properties. Falls dies abweicht, gibt es noch ein Name Property (wie bei dem Tabellen Attribut oben).
Standardmäßig wird dann der DB Wert in das Property geschrieben, welches zugewiesen wurde. Wenn man als Datenhalterobjekt z.B. ein privates Property verwenden möchte, kann man dies über das “Storage” Property zuweisen.

LINQ to SQL – Schritt 2: Die DB Abfrage

In unserer Program.cs wollen wir nun eine einfache Abfrage der Kunden einbauen.

Als erstes müssen wireinen DataContext aufbauen, welchen wir den ConnectionString übergeben. Danach veranlassen wir den Datacontext das Mapping über die GetTable Methode zu “starten”:

DataContext db = new DataContext(@"Data Source=REMAN-NOTEBOOK\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
Table<Customer> Customers = db.GetTable<Customer>();

Um zu sehen, was für SQL Befehle ausgeführt werden, gibt es auch ein Log Property, wo wir unsere Console anheften:

db.Log = Console.Out;

Jetzt zur eigentlichen Abfrage mit LINQ (und der Ausgabe):

            var custs =
                from c in Customers
                where c.City == "London"
                select c;

            foreach (var cust in custs)
            {
                Console.WriteLine("ID={0}, City={1}, Address={2}", cust.CustomerID, cust.City, cust.Address);
            }

Mit der Abfrage werden alle Kunden aus London in “var custs” (das Konzept von “var” ist hier beschrieben) gespeichert.

Hinweis: Mit GetTable<…>() werden noch keine Daten vom SQL Server geholt – erst beim Zugriff auf Customers wird die Abfrage gemacht (Siehe Video).

Ergebnis:

image

Vollständiger Quellcode:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Data.Linq.Mapping;

namespace LinqToSqlTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Use a standard connection string
            DataContext db = new DataContext(@"Data Source=REMAN-NOTEBOOK\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
            Table<Customer> Customers = db.GetTable<Customer>();

            db.Log = Console.Out;

            // Query for customers in London
            var custs =
                from c in Customers
                where c.City == "London"
                select c;

            foreach (var cust in custs)
            {
                Console.WriteLine("ID={0}, City={1}, Address={2}", cust.CustomerID, cust.City, cust.Address);
            }

            Console.ReadLine();
        }
    }
}

LINQ to SQL – Schritt 3: Änderung an der DB vornehmen – einen neuen Eintrag anfügen

Ein neuen Eintrag hinzufügen geht recht schnell:

            Customer newCostumer = new Customer();
            newCostumer.City = "Dresden";
            newCostumer.Address = "Riesaer Str. 5";
            newCostumer.CustomerID = "DDMMS";
            newCostumer.CompanyName = "T-Systems MMS";

            Customers.InsertOnSubmit(newCostumer);
            db.SubmitChanges();

Hierbei musste ich aber noch ein neues Property für den Costumer hinzufügen: CompanyName – weil dieser (ebenso wie CustomerID) NOT NULL sein muss:

image

Wie oben zu sehen ist, wird einfach ein neuer Customer angelegt und über Customers wird dieses Objekt an (die wir über den DataContext bekommen haben) die Methode “InsertOnSubmit” weitergereicht und dort vorgemerkt, beim “Submitten” in die DB eingetragen zu werden.

Das “Submitten” wird über “SubmitChanges” vom DataContext gestartet.

LINQ to SQL – Schritt 4: Änderung an der DB vornehmen – einen Eintrag editieren

Das Dateneditiere wird direkt an den Objekten vorgenommen:

            var upObjects = from test in Customers
                             where test.CompanyName == "T-Systems MMS"
                             select test;

            upObjects.First().Address = "Straße";
            db.SubmitChanges();

Hier erfolgt nur ein “SubmitChanges” und der erste gefundene Eintrag (über First()) wird entsprechend geändert.

LINQ to SQL – Schritt 5: Änderung an der DB vornehmen – einen Eintrag entfernen

Den eben angelegten Eintrag kann man auch wieder entfernen:

var delObjects = from test in Customers
                             where test.CompanyName == "T-Systems MMS"
                             select test;

            Customers.DeleteOnSubmit(delObjects.First());
            db.SubmitChanges();

Hier holen wir uns einfach unser eben erstelltes Objekt wieder und nehmen wieder über die First() Methode das erste gefundene (da es sowieso nur einen Eintrag dort gibt) Ergebnis. Löschen kann man es einfach über “DeleteOnSubmit“.

Der gesamte Source Code (download weiter unten):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Data.Linq.Mapping;

namespace LinqToSqlTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Use a standard connection string
            DataContext db = new DataContext(@"Data Source=REMAN-NOTEBOOK\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
            Table<Customer> Customers = db.GetTable<Customer>();

            // Logging
            db.Log = Console.Out;

            // CREATE
            Customer newCostumer = new Customer();
            newCostumer.City = "Dresden";
            newCostumer.Address = "Riesaer Str. 5";
            newCostumer.CustomerID = "DDMMS";
            newCostumer.CompanyName = "T-Systems MMS";

            Customers.InsertOnSubmit(newCostumer);
            db.SubmitChanges();

            // READ
            var custs =
                from c in Customers
                where c.City == "Dresden"
                select c;

            // Debugging - Console.WriteLine
            foreach (var cust in custs)
            {
                Console.WriteLine("ID={0}, City={1}, Address={2}", cust.CustomerID, cust.City, cust.Address);
            }

            // UPDATE
            var upObjects = from test in Customers
                             where test.CompanyName == "T-Systems MMS"
                             select test;

            upObjects.First().Address = "Straße";
            db.SubmitChanges();

            // Debugging - Console.WriteLine
            foreach (var cust in custs)
            {
                Console.WriteLine("ID={0}, City={1}, Address={2}", cust.CustomerID, cust.City, cust.Address);
            }

            // DEL
            var delObjects = from test in Customers
                             where test.CompanyName == "T-Systems MMS"
                             select test;

            Customers.DeleteOnSubmit(delObjects.First());
            db.SubmitChanges();

            Console.ReadLine();
        }
    }
}

Wichtiger Hinweis:

Die Anwendung läuft nur einmal durch, da die CustomerID eindeutig sein muss – aber das hier soll nur der Anfang sein um LINQ to SQL mehr zu verstehen.
Das die LINQ Abfragen hier sicherlich verbesserungswürdig sind, ist eine andere Sache (und wird sicherlich in einem anderen HowTo unterkommen).

Das Mapping erfolge hier sehr einfach über das manuelle dazu schreiben der Attribute – es gibt einen direkten LINQ to SQL Designer.

Empfehlung an alle die sich für LINQ to SQL interessieren:

Das HoL über LINQ to SQL, was ich bereits oben erwähnt hatte, geht noch auf andere Aspekte ein. Einige davon werde ich sicherlich selber noch in HowTos packen, allerdings bis dahin dient es als gute Anlaufstelle zu Themen wie:

  • LINQ to SQL Designer
  • Beziehungen zwischen einzelnen Tabellen modellieren
  • Streng-typisierte DataContext Objekte
  • Transaktionen (Sehr interessantes Thema!)
  • Mapping a stored procedure

Das Thema wird sicherlich bei mir noch häufiger anzutreffen sein (und das war heute mein erster richtiger Berührungspunkt mit LINQ to SQL – ich hoffe, dass das Konzept (und wie es intern tickt) etwas klarer ist ;) )

[ Download Demoanwendung ]

HowTo: C# 3.0 – "var" Keyword und andere kleine C# 3.0 Features verstehen

Mit .NET 3.5 kam auch C# 3.0 (und die entsprechende VB Variante, die hier aber nicht behandelt wird) ans Licht der Welt. Für die Entwicklung von .NET 3.5 Applikationen ist Visual Studio 2008 Pflicht – die Express Variante kann man sich kostenlos bei Microsoft runterladen.

In diesem HowTo geht es um das neue Keyword “var“, andere Featues wie Lamda Expressions, LINQ, Partielle Methoden werden später bestimmt ebenfalls noch Themen werden.

Für einen gute Komplettübersicht empfehle ich das C# 3.0 Language Enhancements Hands on Lab.

Was ist “var”?

Mittels “var” ist es möglich einem Object einen anonymen Typ zuzuweisen. Dabei weist der Compiler dann eine entsprechende Klasse oder eine anonyme Klasse zu. Trotz dessen, ist das Object immernoch typisiert. Am besten sieht man dies an einem kleinen Beispiel:

 var IntVar = 15;
 var StringVar = "Hello";
 var ComplexVar = new DateTime();

“IntVar” wird automatisch zum Typ “int”, “StringVar” zu “string” und “ComplexVar” zu “DateTime”. Beweis:

image

Ein einmal zugewiesener Typ, kann nur durch Casting oder Ähnliches in einen anderen Typ konvertiert werden – also wie früher:

var IntVar = 15;
IntVar = 13.5;

Dies bringt folgenden Fehler beim Kompilieren:

image

Wofür braucht man “var” dann?

Wenn man am Ende trotzdem nur einmal den Typ festlegen kann, wozu sollte ich dann überhaupt “var” schreiben, wenn ich gleich “string” etc. hinschreiben könnte?
Folgender Sachen sind mit “var” möglich und daher in diesen Fällen auch interessant:

  • 1. In Zusammenhang mit LINQ kann man sich sein “Result” Typ so zusammenbauen, wie man ihn braucht, ohne das er vorher existierte.
  • 2. Man kann einen komplexes Objekt “on-the-fly” erstellen.

Eine Sache sollte natürlich klar sein: “var” sollte nur dort Verwendung finden, wo es sinnvoll ist – wenn der Typ ohnehin bekannt und da ist, braucht man es schonmal nicht.

Das Demoprojekt – ein Konsolenprogramm zum Testen der neuen Features

Nachfolgend müssen wir einige Sachen vorbereiten, um am Ende das “var” Keyword sinnvoll zu gebrauchen.

Als erstes brauchen wir mal eine kleine Klasse, damit wir etwas experimentieren können:

    public class Product
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }

C# 3.0 Neuerung hierbei: Das Feature mit “get; set;” ist ebenfalls neu in C# 3.0. Damit entfällt das etwas lästige “private string blub; public string Blub {…}” –

Danach legen wir in “Main” ein neues Produkt an:

Product MyProduct = new Product { Name = "Auto", Id = 123 };

C# 3.0 Neuerung hierbei: Ebenfalls neues Feature und wird in Visual Studio 2008 auch über die IntelliSense angezeigt:

image 

Und auch eine Liste an Produkten wird angelegt:

List<Product> MyProductList = new List<Product>
            {
                new Product { Name = "Brett", Id = 1 },
                new Product { Name = "Bett", Id = 2 },
                new Product { Name = "Pfanne", Id = 3 }
            };

C# 3.0 Neuerung hierbei: Auch Listen oder Arrays können so angelegt werden. Alles natürlich mit IntelliSense.

Dann legen wir noch 2 andere Objekte an:

var MyVarString = "Something...";
var MyVarInt = 13;

C# 3.0 Neuerung hierbei: Wie bereits oben geschrieben – das “var” Keyword.

Das “var” Keyword benutzen, um einen komplexen anonymen Typ zu erstellen

            var MyVarComplex = new {
                                    Product = new Product { Name = "Kette", Id = 33},
                                    AnotherProduct = MyProduct,
                                    SimilarProducts = MyProductList,
                                    Information = "This is an additional information.",
                                    SpecialId = MyVarInt,
                                    SpecialString = MyVarString
                                };

 

“MyVarComplex” ist nun unser komplexer, anonymer Typ, welchen wir on-the-fly über das “var” Keyword erstellen:

Über “new { … }” legt man einen solchen anonymen Typ an. “AnotherProduct” ist z.B. eines unserer Attribute des anonymen Typs und wird mit “MyProduct” befüllt.

image

Besonders interessant: “MyVarComplex” wird als “Anonymous Type” angegeben.

Natürlich bietet Visual Studio volle IntelliSense Unterstützung:

image 

Was haben wir jetzt davon?

Manchmal benötigt man Daten in einer speziellen Form, von verschiedenen Objekten – bis jetzt musst man entweder über unschönen Notlösungen mit “object” oder halt das erstellen einer entsprechenden Klasse sowas lösen. Mit “var” ist es jedoch sehr einfach, einen entsprechenden Objektbaum schnell zu erstellen.
Zusammen mit den anderen C# 3.0 Features die hier vorgestellt wurden, aber auch LINQ und co., ist das ein großer Schritt nach vorn.

Hier der gesamte Source Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Product MyProduct = new Product { Name = "Auto", Id = 123  };

            List<Product> MyProductList = new List<Product>
            {
                new Product { Name = "Brett", Id = 1 },
                new Product { Name = "Bett", Id = 2 },
                new Product { Name = "Pfanne", Id = 3 }
            };

            var MyVarString = "Something...";
            var MyVarInt = 13;

            var MyVarComplex = new {
                                    Product = new Product { Name = "Kette", Id = 33},
                                    AnotherProduct = MyProduct,
                                    SimilarProducts = MyProductList,
                                    Information = "This is an additional information.",
                                    SpecialId = MyVarInt,
                                    SpecialString = MyVarString
                                };

            Console.ReadLine();
        }
    }

    public class Product
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }
}

Als Download:

[ Download Democode ]

Links: