user2619500
user2619500

Reputation: 21

Calling a generic function when type is only known at execution time

I have a generic function that looks like this:

public static class ExcelImport
{
    public static List<T> Test<T>(string filename, string worksheetname) where T : class
    {
        return new List<T>(ExcelImport.Parse<T>(filename, worksheetname));
    }
    ...
}

If I know on what type of objects I will perform the test function, I can easily call it that way (for example):

List<OEE.Data.Equipment> result = ExcelImport.Test<OEE.Data.Equipment>(fileName.Text, worksheetName.Text);

But the fact is that Test can be applied to any class of the OEE.Data namespace and users will select the right class in a combobox just before launching Test function.

I could use a switch to link a different call for each combobox value but this means that I'll have to had new cases anytime I'll add classes to OEE.Data. So, how can I give the type dynamically? The code below is not working:

List<Type.GetType("OEE.Data.Equipment")> result = ExcelImport.Test<Type.GetType("OEE.Data.Equipment")>(fileName.Text, worksheetName.Text);

Thanks in advance!

Simon

Edit: In answer to the comment under Dishold's response, here is the code that's behind my call to the Test method:

public static List<T> Test<T>(string filename, string worksheetname) where T : class
{
    return new List<T>(ExcelImport.Parse<T>(filename, worksheetname));
}

private static IEnumerable<K> Parse<K>(string filename, string worksheetname) where K : class
{
    IEnumerable<K> list = new List<K>();
    string connectionString = string.Format("provider=Microsoft.Jet.OLEDB.4.0; data source={0};Extended Properties=Excel 8.0;", filename);
    string query = string.Format("SELECT * FROM [{0}]", worksheetname);

    DataSet data = new DataSet();

    using (OleDbConnection con = new OleDbConnection(connectionString))
    {
        con.Open();
        OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
        adapter.Fill(data);
        list = PopulateData<K>(data);
    }

    return list;
}

private static List<T> PopulateData<T>(DataSet data) where T : class
{
    List<T> dtos = new List<T>();

    foreach (DataRow row in data.Tables[0].Rows)
    {
        T dto = Activator.CreateInstance<T>();

        PopulateFieldsFromDataRows(row, dto);
        dtos.Add(dto);
    }

    return dtos;
}

The new problem is now in method PopulateData, because I can't create an instance of System.RuntimeType like here:

T dto = Activator.CreateInstance<T>();

Upvotes: 2

Views: 258

Answers (2)

user2619500
user2619500

Reputation: 21

I finally found the problem why I was not getting the right type (getting System.RuntimeType instead).

To be short: I was reading all the types in an assembly (my model) and adding all of these as items in a devexpress combobox.

But when I wanted to take the selected item from the combobox, looks like I was not getting the good type. So, I finally iterated again on the types from my assembly till I found one with the same name as my selected item (in combobox), and taking that type instead.

Upvotes: 0

Dilshod
Dilshod

Reputation: 3331

Try this:

Type type = Type.GetType("OEE.Data.Equipment");
MethodInfo genericMethod = typeof(ExcelImport).GetMethod("Test").MakeGenericMethod(new Type[]{type});
object result = genericMethod.Invoke(null, new[]{fileName.Text, worksheetName.Text});

UPDATE:

In my example I am using SQL database, you can easily convert it to OLEDB. I have SQL Database that has table Customer.

It has: id uniqueidentifier, name varchar(100), age int, email varchar(100).

Then I created a class called Customer:

    public class Customer
    {
        public Guid Id { get; set; }

        public string Name { get; set; }

        public string Email { get; set; }

        public int Age { get; set; }
    }

I think you know what kind of result you will get from the query. Basically create class that has properties matches with query fields(like Customer). Then you can assign it to using Linq. Let me know if you have any trouble with understanding the code.

            SqlConnection conn = new SqlConnection("data source=localhost;initial catalog=Test;integrated security=True");
            conn.Open();
            SqlCommand command = new SqlCommand("SELECT * FROM Customer", conn);
            DataSet dataSet = new DataSet();
            SqlDataAdapter adapter = new SqlDataAdapter(command);
            adapter.Fill(dataSet);
            var a = (from d in dataSet.Tables[0].Rows.Cast<DataRow>()
                    select new Customer() {
                        Id = (Guid)d[0],
                        Name = d[1].ToString(),
                        Age = Convert.ToInt32(d[2]), 
                        Email = d[3].ToString()
                    }).ToList();

I hope that helps,

Upvotes: 1

Related Questions