2010-04-14 51 views
3

我有一個數字,包含表像這樣的靜態類:從DataTable獲取單個值的最佳方法?

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

有沒有寫數據1或數據2的方法,從單個行給定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."); 
    } 
} 

我的數據1方式變爲:

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代碼單行。

+0

至少你應該重構這兩個函數。唯一的區別是Data1和Data2。除此之外,它看起來像我會用一個無類型的數據集。 – 2010-04-14 12:51:40

+0

我同意重構,但這只是一個例子,Data1或Data2可能根據所選的id做不同的事情。我只是認爲可能會有更優雅的選擇單個項目的方式。 – 2010-04-14 13:12:13

回答

3

您是否考慮過使用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 - 單行代碼是什麼樣的? – 2010-04-14 13:03:17

+1

我的猜測是,他是有所指,這樣'INT DATA1 = dt.Rows.OfType ()。凡(行=>(int)的行[ 「ID」] == 1)。選擇(行=>(INT )行[ 「數據1」])第一(); 雙DATA2 = dt.Rows.OfType ()。凡(行=>(int)的行[ 「ID」] == 1)。選擇(行=>(雙)行[ 「數據2」])。首先( );' – 2010-04-14 13:10:00

+0

與LINQ看來我需要創建一個EnumerableRowCollection,然後遍歷它只是爲了獲得一個單行/價值 – 2010-04-14 13:14:20

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

的函數處理任何類型的你一般給它,絃樂,其他值類型,可空類型,引用類型。如果該字段爲空,則該函數返回該類型的「默認」值(「」爲字符串)。如果它絕對不能進行轉換,因爲您要求進行不可能的轉換,它會引發錯誤。我已經將它作爲數據行類型的擴展方法(稱爲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 
相關問題