【问题标题】:Create a sequence of anonymous types from the rows in a DataTable从 DataTable 中的行创建一系列匿名类型
【发布时间】:2014-02-20 10:06:17
【问题描述】:

这是一个“让我们看看能不能完成”的练习。

假设我有一个包含几列的 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);
}

但这需要在 new 子句中对属性名称进行硬编码,而我希望属性名称来自 DataTable 的 Columns 集合。

我希望我已经足够清楚地解释了这一点。在玩了一会儿之后,我开始认为,就可读性和可维护性而言,我想出的任何东西都会是一团糟,但我想我会问。

【问题讨论】:

  • 匿名类型是一种编译时机制,它不会等到运行时才描述自己。但是假设您可以解决这个问题,您可以让运行时找出您的属性名称和类型并围绕它构建一个类型。你将如何在编译时使用它?说实话,如果你处于这种困境中,要么保留DataTable,要么花时间正确定义类型(匿名或其他)。

标签: c# linq anonymous-types system.data.datatable


【解决方案1】:

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

您想要做的将需要在运行时构造一个动态类型。

【讨论】:

  • 我想会是这样,然后 Anthony 在上面的评论中提醒我匿名类型的编译时间性质。
【解决方案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;
    }
}

我不确定您的用例是什么,但如果您认为动态是匿名类型的可接受替代品,希望这能帮助您指明正确的方向。

【讨论】:

    猜你喜欢
    • 2011-04-29
    • 2010-11-05
    • 1970-01-01
    • 2016-01-30
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-25
    相关资源
    最近更新 更多