Using anonymous types to shape data

Lets say you are writing a piece of software for a call center to use and you need to display values from multiple classes in your object model in a single DataGridView...

The problem is that you cannot bind a datagridview column to a second-level property without writing TypeDescriptionProvider and CustomTypeDescriptor for each class that we want to use.
Email Image

To get around this limitation we could define an intermediate class which we set the properties on, however we then need to write a class which is only used for one thing to support this. Fortunately we can use anonymous types in .net 3 to help.

Lets define a Person class and an Address class.

public class Person
{
    public string Title { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public DateTime DOB { get; set; }
    public Address Address { get; set; }
    public void DoStuff()
    {
        MessageBox.Show("Person.DoStuff called");
    }
}

public class Address
{
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string Line3 { get; set; }
    public string PostCode { get; set; }
}

Now we need to use a Linq query to select an anonymous type from the collection and shape the data as needed.

var peeps = from person in people
    select new
    {
        Forename = person.Forename,
        Surname = person.Surname,
        DateOfBirth = person.DateOfBirth,
        AddressLine1 = person.Address.Line1,
        PostCode = person.Address.PostCode
    };

We can then use this collection as a data source for our DataGridView.

this.dataGridView1.DataSource = new BindingSource { DataSource = peeps };

Now, lets say that once an identity has been verified, we want to click the person which would bring up their account details. Since we are using the anonymous type, we have no way to get back to the Person that we built the anonymous type from... actually, with a little bit of reflection we can!

The way to do it (with 3 additional lines of code) is to add a property with a specific name to the anonymous type which we know beforehand and will always use when doing this kind of activity. I suggest a name like DataEntityObject. To use it, we add 1 additional line to the declaration of the anonymous type.

var peeps = from person in people
    select new
    {
        DataEntityObject = person,
        Forename = person.Forename,
        Surname = person.Surname,
        DateOfBirth = person.DateOfBirth,
        AddressLine1 = person.Address.Line1,
        PostCode = person.Address.PostCode
    };

Now to get hold of that DataEntityObject, we need the following helper method. This method will either return null if there is no property called DataEntityObject or it will return the object that is presented as the DataEntityObject property on our anonymous type.

private object GetDataEntityObjectFromAnonymousType(object anonymousObject)
{
    // Get the anonymous type's Type so that we can get a property from it.
    Type anonymousObjectType = anonymousObject.GetType();

    // If the dataItemType does not have a DataObject property return null,
    // otherwise return the DataObject behind the property.
    return (anonymousObjectType.GetProperty("DataEntityObject") == null)
        ? null
        : anonymousObjectType.GetProperty("DataEntityObject").GetValue(anonymousObject, null);
}

We can then reference the selected person and call methods or set properties.

Person person =
    (Person)GetDataEntityObjectFromAnonymousType(this.dataGridView1.SelectedRows[0].DataBoundItem);

person.DoStuff();

To stop the DataEntityObject from being shown in the DataGridView, you can leverage the code in my Custom DataGridView Column Headings tutorial.


This article was published on the 3rd August 2008 and last updated 4th August 2009
Licence information / Terms of use

All code supplied on this site be it within the assembly or code samples is supplied as is. I take no responsibility for any of the code provided. As always with code samples & frameworks, use it at your own risk.

All applications and tutorials where C# code is provided in either text or a class file may be freely used and modified if you so desire.

The assembly is compiled against .net 3.5. There will not be a 2.0 compatible version so if you wish to use the assebly you will need to be using Visual Studio 2008 with the .net 3.5 framework installed.

The assembly may be used within in commercial and personal software free of charge but may not be resold on its own. To clarify, you may build an application on top of any of the functionality provided by the assembly (e.g using the code contract framework inside your application).

Support, suggestions and bugs can be submitted via my contact form however it is offered on a limited basis with no guaranteed response or response time.

Any updates or bug fixes will be included in any further downloads once releases on the site but note that there is no "update" service available so you would need to manually update any code.