Установка всех свойств динамического объекта в анонимном типе в запросе linq
Мне нужно конвертировать динамические объекты (т.е. List<DynamicRow>
) в список объектов анонимного типа, но мне нужно, чтобы все свойства динамического объекта создавались в объект анонимного типа во время выполнения с использованием linq или каким-либо другим способом.
Это возможно? Если да, то как мне это сделать?
Этот динамический объект в значительной степени является классом сетки, где он содержит список столбцов, т.е. List<String>
и строки то есть List<DynamicRow>
,
Я могу получить доступ к значению, содержащемуся в объекте DynamicRow (например, Order), используя имя столбца, т.е. Order[<columnName>] -> Order["OrderNumber"]
Я надеюсь, что смогу сделать то же самое с помощью Linq.
Есть ли способ перебрать список столбцов и создать анонимный тип объекта для каждой строки, где каждое свойство устанавливается на основе имени столбца.
Хотя я знаю, что приведенный ниже код не работает, он может сделать немного более понятным то, чего я пытаюсь достичь:
Итак, иметь это:
var itemsList = from p in customerOrderCsvReader
select new
{
Item = p.ElementAt(0).Value,
Description = p.ElementAt(1).Value,
Comment = p.ElementAt(2).Value
};
Я хотел бы иметь что-то вроде этого, так как я не буду заранее знать имя свойства, такое как Item, Description и Comment. Единственный способ узнать, что находится в динамическом объекте, это использовать имя столбца.
var itemsList = from p in customerOrderCsvReader
select new
{
foreach string columnName in customerOrderCsvReader.columnNames
{
<columnName as property> = p.ElementAt(0).Value;
}
};
Другая проблема, если предположить, что вышеупомянутое, выполнимо, есть ли у меня способ доступа к свойству p с помощью ключа, например columnName, а не p.ElementAt.
ОБНОВЛЕНО
Я, вероятно, должен был быть более ясным. Я пытаюсь привязать это к сетке, но я также пытаюсь сохранить этот универсальный, чтобы он работал на любой платформе, а не только winform.
Если я использую код, предоставленный @jjchiw, я получаю следующее при выводе этого в окно вывода:
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}
Но если я использую linq и предоставляю некоторые фиктивные имена свойств и присваиваю им некоторые значения, используя что-то вроде этого:
var itemsList = from p in customerOrderCsvReader
select new
{
CustomerId = p.ElementAt(0),
EmployerId = p.ElementAt(1),
Description = p.ElementAt(2)
};
Я получаю следующий вывод в мое окно вывода:
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" }
При привязке динамического списка к моей сетке он ничего не отображает, но при использовании списка анонимных типов, который теперь технически содержит список "распознаваемых" объектов, моя сетка, отображает данные соответствующим образом.
Есть ли способ заставить динамический список вести себя как анонимный, чтобы я мог привязать динамический список к своей сетке, но получить правильные результаты?
1 ответ
Создание ExpandoObject и приведение как IDictionary<string, object>
должен делать то, что вы хотите, что-то вроде этого
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"]);
РЕДАКТИРОВАТЬ.
Я нашел эту библиотеку ImpromptuInterface ( nuget), и я вспомнил об этом вопросе, может быть, это не то, что вы ищете, так как в этом решении вам нужно определить интерфейсы для Datagrid, и вы хотите, чтобы все было анонимно... в любом случае было интересно заполнить 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; }
}