Tengo un número de clases estáticas que contienen tablas como esta:

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

Existe una mejor manera de escribir la Data1 o Data2 métodos que devuelven un único valor de una sola fila que coincide con el id?

Actualización #1:

He creado un método de extensión que parece bastante agradable:

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.");
}
}

Mi Data1 método se convierte entonces en:

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

y Data2 se convierte en:

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

Gracias a todas sus respuestas, pero especialmente a Anthony Pegram que dio el muy agradable sola línea de LINQ & Lambda código.

  • al menos hay que refactorizar esas dos funciones. La única diferencia es el Data1 y Data2. Aparte de que esto se parece a lo que yo haría con un conjunto de datos sin tipo.
  • Estoy de acuerdo con la refactorización, sin embargo, esto fue sólo un ejemplo y Data1 o Data2 puede hacer cosas diferentes dependiendo del id seleccionado. Pensé que sólo puede haber una forma más elegante de la selección de un único elemento.
InformationsquelleAutor Piers Myers | 2010-04-14

2 Comentarios

  1. 3

    Han considerado que el uso de Linq (para conjuntos de datos)? Con expresiones Linq que no necesitan de esas Data1 y Data2 funciones a todos desde las operaciones de búsqueda y filtrado que podría suceder en una sola línea de código.

    Ejemplo añadido:

    Disparo desde la cadera aquí, así que por favor tomar con un grano de sal (no cerca de una IDE:)

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

    Que dos líneas de código pero fácilmente podría envolver la obtención de la Enumerable.

    • Yo sería feliz a utilizar LINQ – ¿qué sería de la única línea de código parece?
    • Mi conjetura es que él estaba dando a entender algo como esto 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();
    • con LINQ parece que necesita para crear un EnumerableRowCollection y luego iterar a través de él sólo para obtener una sola fila/valor
    • Gracias Anthony Pegram, he incorporado tu respuesta – ver mi actualización #1 arriba. Me gustaría dar las garrapatas para usted si usted había respondido como una respuesta en lugar de un comentario 🙂
    • Me alegro de haber contribuido.
  2. 0

    Estoy un poco sospechoso de su arquitectura, pero no importa eso. Si desea una función que devuelve el primer valor de la primera fila de una tabla de datos que va a conseguir de alguna manera, y que desea es inflexible, creo que la siguiente función será una mejora. Permite tener sólo una función, reutilizables para los diferentes tipos. Para el uso que tienen las líneas de código como:

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

    y si te apetece:

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

    La función maneja cualquier tipo que genéricamente a darle, cadenas, otros tipos de valores, tipos que aceptan valores null, los tipos de referencia. Si el campo es null, la función devuelve el valor «predeterminado» para que escriba («» para la cadena). Si no puede hacer la conversión, por pedir un imposible la conversión, se producirá un error. Me he hecho un método de extensión en el datarow tipo (llamado ValueOrDefault), y este tonto es realmente útil.

    He adaptado este tipo de datos-herramienta del método de extensión de la mina para su situación. Estoy en un VB de la tienda, y yo simplemente no tienen tiempo para volver a escribir todo esto en C#, pero que se podía hacer eso con bastante facilidad.

    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

Dejar respuesta

Please enter your comment!
Please enter your name here