Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a sequence of anonymous types from the rows in a DataTable

This is a "let's see if it can be done" exercise more than anything else.

Suppose I have a DataTable with several columns. Using linq, is it possible to select the rows of the table such that the result will be a sequence of an anonymous type where each property of the anonymous type is named according to the column name of the DataTable and the type of each property is set appropriately.

So if my DataTable has three columns like so:

Name = "Column1",  DataType = string
Name = "Column2",  DataType = integer
Name = "Column3",  DataType = bool

Then I want to select all the rows of the DataTable such that the anonymous type has three properties:

DataSet ds = functionThatGetsADataSet();
var seq = ds.Tables[0].AsEnumerable().Select( r => **** MAGIC HERE ****)

foreach (var s in seq)
{
    Console.WriteLine(s.Column1);
    Console.WriteLine(s.Column2);
    Console.WriteLine(s.Column3);
}

I know that I can do this:

DataSet ds = functionThatGetsADataSet();
var seq = ds.Tables[0].AsEnumerable().Select( r => 
   new 
   {
       Column1 = r.Field<string>("Column1"),
       Column2 = r.Field<int>("Column2"),
       Column3 = r.Field<bool>("Column3"),
   }
)

foreach (var s in seq)
{
    Console.WriteLine(s.Column1);
    Console.WriteLine(s.Column2);
    Console.WriteLine(s.Column3);
}

but this requires hard coding the property names in the new clause, whereas I would like the property names to come from the Columns collection of the DataTable.

I hope that I have explained this clearly enough. After playing around with this for a little bit, I am beginning to think that anything that I come up with will be a big mess as far as readability and maintainability goes, but I thought I would ask.

like image 694
Chris Dunaway Avatar asked Jun 15 '11 20:06

Chris Dunaway


2 Answers

I'm afraid that there is no such magic (at least not with anonymous types). Anonymous types are implicit types generated by the compiler as immutable classes with their properties named & typed by the explicit assignment operation like in your second example (at compile time).

What you're wanting to do would require a dynamic type constructed at run time.

like image 106
Brandon Moretz Avatar answered Sep 27 '22 18:09

Brandon Moretz


As already established in Brandon's answer, this can't be done with Anonymous types, as they are generated at compile time. However, as mentioned, you can make use of dynamics to get a similar syntax.

For example, you could get the following syntax (based on your example):

var seq = table.AsEnumerable().Select(row => (dynamic)new DynamicDataRow(row));
foreach (var s in seq)
{
    Console.WriteLine(s.Column1);
    Console.WriteLine(s.Column2);
    Console.WriteLine(s.Column3);
}

Using a simple dynamic wrapper for your DataRows:

class DynamicDataRow : DynamicObject
{
    private readonly DataRow row;

    public DynamicDataRow(DataRow row)
    {
        this.row = row;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        DataColumn column = row.Table.Columns[binder.Name];
        if (column != null)
        {
            result = row[column];
            return true;
        }

        result = null;
        return false;
    }
}

I'm not exactly sure what your use case is, but hopefully this helps point you in the right direction if you decide that dynamics are an acceptable substitute for anonymous types.

like image 42
Matthew King Avatar answered Sep 27 '22 19:09

Matthew King