我需要将动态对象(即List<DynamicRow>
)转换为匿名类型对象的列表,但我需要在运行时将动态对象的所有属性创建为匿名类型对象,使用linq或其他一些方式。
这可能吗?如果是这样,我该怎么做?
这个动态对象几乎是一个网格类,它包含一列列,即List<String>
和行List<DynamicRow>
。
我可以使用列名Order[<columnName>] -> Order["OrderNumber"]
来访问DynamicRow对象(例如Order)中保存的值,所以我希望能够使用Linq执行相同的操作。
是否有办法遍历列列表并为每行创建一个匿名对象类型,其中每个属性都是根据列名设置的。
虽然我知道下面的代码不起作用,但它可能会使我想要的更清晰:
所以有这个:
var itemsList = from p in customerOrderCsvReader
select new
{
Item = p.ElementAt(0).Value,
Description = p.ElementAt(1).Value,
Comment = p.ElementAt(2).Value
};
我想有这样的东西,因为我不会事先知道物品名称,如物品,描述和评论。我知道动态对象中的内容的唯一方法是使用列名。
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" }
将动态列表绑定到我的网格时,除了使用匿名类型列表(在技术上现在包含“可识别”对象列表)时,它不会显示任何内容,我的网格会相应地显示数据。
无论如何强制动态列表的行为类似于匿名列表,这样我就可以将动态列表绑定到我的网格,但会显示正确的结果。
答案 0 :(得分:2)
创建一个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"]);
EDIT。
我找到了这个图书馆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; }
}