Nick LaMarca
Nick LaMarca

Reputation: 8188

Invalid Arguments Error Using Generics

I am trying to use the function found here: DataTable to List<object>

  public static IList<T> ConvertTo<T>(DataTable table)
        {
            if (table == null)
                return null;

            List<DataRow> rows = new List<DataRow>();

            foreach (DataRow row in table.Rows)
                rows.Add(row);

            return ConvertTo<T>(rows);
        }

the return statement is giving me an exception stating:

The best overloaded method match for 'Utilities.Utility.ConvertTo<T>(System.Data.DataTable)' has some invalid arguments

Can someone help me fix this error??

Upvotes: 0

Views: 1451

Answers (2)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112259

First, you are returning a T but not a IList<T>. Secondly, how are you expecting a DataRow to be converted to an unknown T, especially if a row has several columns?

Try something like this

public static IList<IList<T>> ConvertTo<T>(DataTable table)
{
    if (table == null)
        return null;
    List<IList<T>> rows = new List<IList<T>>();
    foreach (DataRow row in table.Rows) {
        rows.Add(row.ItemArray.Cast<T>().ToArray());
    }
    return rows;
}

UPDATE:

A custom object is something like this

public class Employee
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Salary { get; set; }
}

However, in that case a generic interface is not useful, since you would have to code for that specific class

public static IList<Employee> GetEmployees(DataTable table)
{
    var employees = new List<Employee>();
    if (table != null) {
        foreach (DataRow row in table.Rows) {
            var emp = new Employee();
            emp.ID = (int)row["ID"];
            emp.Name = (string)row["Name"];
            emp.Salary = (decimal)row["Salary"];
            employees.Add(emp);
        }
    }
    return employees;
}

This code has to be different for different tables and cannot be generic. At least not without using Reflection and assuming that the properties have the same names as the table columns.


A solution not using some tricky Reflection code or other magic tricks would be to define an interface like this

public interface IDataObject
{
    void FillFromRow(DataRow row);
}

Then you declare Employee or any other data classes like this

public class Employee : IDataObject
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Salary { get; set; }

    public void FillFromRow(DataRow row)
    {
        ID = (int)row["ID"];
        Name = (string)row["Name"];
        Salary = (decimal)row["Salary"];
    }
}

Now you can use generics again

public static IList<T> GetItems<T>(DataTable table)
    where T : IDataObject, new()
{
    var items = new List<T>();
    if (table != null) {
        foreach (DataRow row in table.Rows) {
            T item = new T();
            item.FillFromRow(row);
            items.Add(item);
        }
    }
    return items;
}

Upvotes: 1

Hogan
Hogan

Reputation: 70513

Don't do it that way use Marc's amazing function ( https://stackoverflow.com/a/545429/215752 ) I mean really... that is exactly what you want.. right?


You need another function

public static IList<T> ConvertTo<T>(IList<DataRow> rows)
    {
        IList<T> list = null;

        if (rows != null)
        {
            list = new List<T>();

            foreach (DataRow row in rows)
            {
                T item = CreateItem<T>(row);
                list.Add(item);
            }
        }

        return list;
    }

The question you link had a link in it. I'd suggest looking there for more info:

http://lozanotek.com/blog/archive/2007/05/09/Converting_Custom_Collections_To_and_From_DataTable.aspx

There you will find all the code, which I expect will compile. I won't vouch for the reliability or reasonably of using it however.

Upvotes: 1

Related Questions