سؤال

I need to convert dynamic objects (i.e. List<DynamicRow>) to a List of anonymous type objects but I need to have all the properties of the dynamic object to be created into an anonymous type object at run time either using linq or some other way.

Is this possible? If so, how do I do this?

This dynamic object is pretty much a grid class where it contains a list of columns i.e. List<String> and the rows i.e. List<DynamicRow>.

I can access the value held in a DynamicRow object (Order for example) using the column name i.e. Order[<columnName>] -> Order["OrderNumber"], so I hope to be able to do the same using Linq.

Is there a way to loop through the list of columns and create an anonymous object type for each row where each property is set based on the column name.

While I know the code below doesn't work, it might make what I'm trying to achieve a bit clearer:

So intead of having this:

var itemsList = from p in customerOrderCsvReader
select new
{                            
 Item = p.ElementAt(0).Value,
 Description = p.ElementAt(1).Value,
 Comment = p.ElementAt(2).Value
};

I would like to have something like this as I won't know the Property name like Item, Description and Comment in advance. The only way I know what is in the dynamic object is by using the Column Name.

var itemsList = from p in customerOrderCsvReader
select new
{
 foreach string columnName in customerOrderCsvReader.columnNames
 {
  <columnName as property> = p.ElementAt(0).Value;
 }
};

Another issue, assuming the above is doable, is there a way for me to access the property of p using a key i.e. columnName rather p.ElementAt.

UPDATED

I probably should have been clearer. I'm trying to bind this to a grid, but I'm trying to also keep this generic so it will work on any platform, not just winform.

If I use the code provided by @jjchiw, I get the following when outputting this to my output window:

Count = 6
    [0]: {System.Dynamic.ExpandoObject}
    [1]: {System.Dynamic.ExpandoObject}
    [2]: {System.Dynamic.ExpandoObject}
    [3]: {System.Dynamic.ExpandoObject}
    [4]: {System.Dynamic.ExpandoObject}
    [5]: {System.Dynamic.ExpandoObject}

But if I use linq and provide some dummy property names and assign some values to it using something like this:

var itemsList = from p in customerOrderCsvReader
                select new
                {
                  CustomerId = p.ElementAt(0),
                  EmployerId = p.ElementAt(1),
                  Description = p.ElementAt(2)
                };

I get the following outputted to my output window:

Count = 6
    [0]: { CustomerId = "GREAL", EmployerId = "6", Description = "1997-05-06T00:00:00" }
    [1]: { CustomerId = "HUNGC", EmployerId = "3", Description = "1997-05-06T00:00:00" }
    [2]: { CustomerId = "LAZYK", EmployerId = "8", Description = "1997-05-06T00:00:00" }
    [3]: { CustomerId = "LETSS", EmployerId = "1", Description = "1997-05-04T00:00:00" }
    [4]: { CustomerId = "WALLM", EmployerId = "5", Description = "1997-05-04T00:00:00" }
    [5]: { CustomerId = "TOTAL", EmployerId = "4", Description = "1997-05-06T00:00:00" }

When binding the dynamic list to my grid, it doesn't display anything but when using the anonymous type list, which technically now contains a list of "recognisable" objects, my grid, displays the data accordingly.

Is there anyway to force a dynamic list to behave like an anonymous one so that I can bind the dynamic one to my grid but get the correct results displayed.

هل كانت مفيدة؟

المحلول

Creating an ExpandoObject and Casting as IDictionary<string, object> should do the stuff that you want, something like this

var columnNames = new List<string>{"Foo", "Foo2"};
var customerOrderCsvReader = new List<List<string>>{new List<string>{"Bar", "Bar2"}};


var list = new List<dynamic>();
foreach (var element in customerOrderCsvReader)
{
    var expando = new ExpandoObject();
    var temp = (IDictionary<string, object>) expando;
    int i = 0;
    foreach(string columnName in columnNames)
    {
        temp[columnName] = element[i];
        i++;
    }
    list.Add(expando);
}

//Print Bar
Console.WriteLine (list[0].Foo);
//Print Bar2
Console.WriteLine (list[0].Foo2);

//Print Bar
Console.WriteLine ((list[0] as IDictionary<string, object>)["Foo"]);
//Print Bar2
Console.WriteLine ((list[0] as IDictionary<string, object>)["Foo2"]);

EDIT.

I found this library ImpromptuInterface (nuget) and I remembered about this question maybe is not what you are looking for since in this solution you need to define interfaces for the Datagrid and you want everything anonymous...anyway It was fun to fill the Datagrid

public partial class Form1 : Form
{
    private Dictionary<string, Type> _columnTypes;

    public Form1()
    {
        InitializeComponent();

        _columnTypes = new Dictionary<string, Type>();
        _columnTypes.Add("FooFoo2", typeof(IFoo));
    }



    private void Form1_Load(object sender, EventArgs e)
    {
        var columnNames = new List<string> { "Foo", "Foo2" };
        var customerOrderCsvReader = new List<List<string>> { new List<string> { "Bar", "Bar2" } };

        var type = _columnTypes[string.Join("", columnNames)];

        var type2 = typeof(DataSourceBuilder<>).MakeGenericType(type);
        dynamic dataBuilder = Activator.CreateInstance(type2);  

        var list = dataBuilder.GetDataSource(columnNames, customerOrderCsvReader);
        dataGridView1.DataSource = list;
    }
}

public class DataSourceBuilder<T> where T : class, IDataSource
{
    public List<T> GetDataSource(List<string> columnNames, List<List<string>> customerOrderCsvReader)
    {
        var list = new List<T>();
        foreach (var element in customerOrderCsvReader)
        {
            dynamic expando = new ExpandoObject();
            var temp = (IDictionary<string, object>)expando;
            int i = 0;
            foreach (string columnName in columnNames)
            {
                temp[columnName] = element[i];
                i++;
            }
            var foo = Impromptu.ActLike<T>(temp);
            list.Add(foo);
        }

        return list;
    }
}

public interface IDataSource
{
}

public interface IFoo : IDataSource
{
    string Foo { get; set; }
    string Foo2 { get; set; }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top