2011-06-15 57 views
4

这是一个“让我们看看是否可以完成”的练习。从DataTable的行中创建一个匿名类型的序列

假设我有一个包含多列的DataTable。使用linq,可以选择表的行,使得结果将是一个匿名类型的序列,匿名类型的每个属性根据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); 
} 

但这需要硬编码ne中的属性名称w子句,而我希望属性名称来自DataTable的Columns集合。

我希望我已经解释清楚了。经过一段时间的讨论后,我开始认为,就可读性和可维护性而言,我所提出的任何事情都会是一团糟,但我想我会问。

+1

匿名类型是一种编译时机制,它不会等待直到运行时才描述自己。但是让我们假设你可以解决这个问题,你可以让运行时找出你的属性名称和类型,并围绕它创建一个类型。你打算如何在编译时使用它?真相被告知,如果你处于这种困境中,要么保留'DataTable'或花时间来正确定义类型(匿名或其他)。 – 2011-06-15 20:32:07

回答

3

恐怕没有这样的魔法(至少不是匿名类型)。匿名类型是由编译器生成的作为不可变类的隐式类型,它们的属性名为&,由第二个示例(编译时)中的显式赋值操作类型化。

你想要做的事情需要在运行时构建一个动态类型。

+0

我有点认为会是这种情况,然后安东尼在上面的评论中提醒我了匿名类型的编译时间性质。 – 2011-06-15 22:01:57

1

正如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); 
} 

使用一个简单的动态包装为您的数据行:

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; 
    } 
} 

我不完全相信你的用例是,但希望这有助于指出你在正确的方向,如果你认为动态是一个可接受的替代匿名类型。