这是一个“让我们看看它是否可以完成”运动比其他任何东西都要好。
假设我有一个包含多个列的DataTable。使用linq,是否可以选择表的行,使得结果将是匿名类型的序列,其中匿名类型的每个属性根据DataTable的列名命名,并且每个属性的类型都设置为适当。
因此,如果我的DataTable有三列如此:
Name = "Column1", DataType = string
Name = "Column2", DataType = integer
Name = "Column3", DataType = bool
然后我想选择DataTable的所有行,使匿名类型有三个属性:
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);
}
我知道我可以这样做:
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);
}
但这需要对新子句中的属性名称进行硬编码,而我希望属性名称来自DataTable的Columns集合。
我希望我已经清楚地解释了这一点。在稍微讨论了一下之后,我开始认为,就可读性和可维护性而言,我提出的任何事情都会是一团糟,但我想我会问。
答案 0 :(得分:3)
我担心没有这样的魔法(至少没有匿名类型)。匿名类型是由编译器生成的隐式类型,作为不可变类,其属性名为&amp;通过显式赋值操作键入,如第二个示例中所示(在编译时)。
您想要做的事情需要在运行时构建动态类型。
答案 1 :(得分:2)
正如在Brandon的回答中已经确定的那样,这不能用匿名类型来完成,因为它们是在编译时生成的。但是,如上所述,您可以利用动态来获得类似的语法。
例如,您可以获得以下语法(基于您的示例):
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);
}
为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;
}
}
我不确定你的用例是什么,但希望如果你认为动态是匿名类型的可接受替代品,这有助于指明你正确的方向。