从DataTable中获取单个值的最佳方法是什么?

5

我有许多包含以下表格的静态类:

using System;
using System.Data;
using System.Globalization;

public static class TableFoo
{
    private static readonly DataTable ItemTable;

    static TableFoo()
    {
        ItemTable = new DataTable("TableFoo") { Locale = CultureInfo.InvariantCulture };
        ItemTable.Columns.Add("Id", typeof(int));
        ItemTable.Columns["Id"].Unique = true;
        ItemTable.Columns.Add("Description", typeof(string));
        ItemTable.Columns.Add("Data1", typeof(int));
        ItemTable.Columns.Add("Data2", typeof(double));

        ItemTable.Rows.Add(0, "Item 1", 1, 1.0);
        ItemTable.Rows.Add(1, "Item 2", 1, 1.0);
        ItemTable.Rows.Add(2, "Item 3", 2, 0.75);
        ItemTable.Rows.Add(3, "Item 4", 4, 0.25);
        ItemTable.Rows.Add(4, "Item 5", 1, 1.0);
    }

    public static DataTable GetItemTable()
    {
        return ItemTable;
    }

    public static int Data1(int id)
    {
        DataRow[] dr = ItemTable.Select("Id = " + id);
        if (dr.Length == 0)
        {
            throw new ArgumentOutOfRangeException("id", "Out of range.");
        }

        return (int)dr[0]["Data1"];
    }

    public static double Data2(int id)
    {
        DataRow[] dr = ItemTable.Select("Id = " + id);
        if (dr.Length == 0)
        {
            throw new ArgumentOutOfRangeException("id", "Out of range.");
        }

        return (double)dr[0]["Data2"];
    }
}

有没有更好的方法编写Data1或Data2方法,以返回与给定id匹配的单行中的单个值?

更新#1:

我已经创建了一个扩展方法,看起来非常不错:

public static T FirstValue<T>(this DataTable datatable, int id, string fieldName)
{
    try
    {
        return datatable.Rows.OfType<DataRow>().Where(row => (int)row["Id"] == id).Select(row => (T)row[fieldName]).First();
    }
    catch
    {
        throw new ArgumentOutOfRangeException("id", "Out of range.");
    }
}

我的Data1方法现在变成了:
public static int Data1(int id)
{
    return ItemTable.FirstValue<int>(id, "Data1");
}

数据2变为:

public static double Data2(int id)
{
    return ItemTable.FirstValue<double>(id, "Data2");
}

感谢大家的回复,特别是Anthony Pegram提供了非常好的一行LINQ & Lambda代码。


1
至少你应该重构那两个函数。唯一的区别在于Data1和Data2。除此之外,它看起来像是我用未类型化数据集所做的事情。 - Greg Bogumil
1
我同意重构,但这只是一个示例,并且Data1或Data2可能会根据所选的id执行不同的操作。我只是认为可能有一种更优雅的选择单个项目的方法。 - Piers Myers
2个回答

5

您考虑过使用Linq (to DataSets)吗?使用Linq表达式,您根本不需要Data1和Data2函数,因为查找和过滤可以在一行代码中完成。

添加示例:

这里是随口说的,所以请带着怀疑的态度看待(没有IDE):

DataTable itemTbl = GetItemTable().AsEnumerable();

double dt1 = ((From t In itemTbl Where t.Id = <your_id> Select t).First())["Data1"];

这只是两行代码,但你可以轻松地包装获取 Enumerable。


1
我很乐意使用LINQ - 请问这个单行代码会是什么样子? - Piers Myers
1
我猜他在暗示这样的事情:int data1 = dt.Rows.OfType<DataRow>().Where(row => (int)row["ID"] == 1).Select(row => (int)row["Data1"]).First(); double data2 = dt.Rows.OfType<DataRow>().Where(row => (int)row["ID"] == 1).Select(row => (double)row["Data2"]).First(); - Anthony Pegram
使用LINQ似乎需要创建一个EnumerableRowCollection,然后迭代它才能获取单个行/值。 - Piers Myers
谢谢Anthony Pegram,我已经采纳了你的答案 - 请看我上面的更新#1。如果你回复成为一个答案而不是评论,我会给你打勾的 :) - Piers Myers
@Piers - 很高兴能够做出贡献。 - Anthony Pegram

0

我对你的架构有点怀疑,但不要在意。如果你想要一个函数,它可以返回某个数据表的第一行的第一个值,并且你希望它是强类型的,那么我认为下面的函数会是一个改进。它将允许你只有一个函数,可重复使用于不同的类型。要使用它,你需要像下面这样编写代码:

int intValue = TableFoo.FirstValueOrDefault<int32>(7);
decimal decValue = TableFoo.FirstValueOrDefault<decimal>(7);

如果你感觉愿意的话:

string strValue = TableFoo.FirstValueOrDefault<string>(7);
int? nintValue = TableFoo.FirstValueOrDefault<int?>(7);

该函数可以处理您通用提供的任何类型,包括字符串、其他值类型、可空类型和引用类型。如果字段为null,则该函数将返回该类型的“默认”值(字符串为“”)。如果它绝对无法进行转换,因为您要求进行不可能的转换,它将抛出一个错误。我将其作为数据行类型的扩展方法(称为ValueOrDefault),这个家伙非常方便。
我为您的情况改编了我的数据工具扩展方法。我在VB商店中,没有时间将整个东西重写为C#,但您可以轻松地完成这个任务。
Public Shared Function FirstValueOrDefault(Of T) (ByVal Int ID) As T
    Dim r as datarow = ItemTable.Select("Id = " + id.ToString());
    If r.IsNull(0) Then
        If GetType(T) Is GetType(String) Then
            Return CType(CType("", Object), T)
        Else
            Return Nothing
        End If
    Else
        Try
            Return r.Field(Of T)(0)
        Catch ex As Exception
            Return CType(r.Item(0), T)
        End Try
    End If
End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接