Dynamic T from string

Andreas Mazatis 131 Reputation points
2022-07-27T20:13:31.673+00:00

I have a method that reads a database table. The name is passed dynamically. Another method gets the table name only as a string and should call the method to read the data. How can I convert a string to a generic T type so that the data read method can be called.

    var ts = "DataTableClass";  

    List<ts> data = reader.TableToList<ts>();  
Developer technologies C#
{count} votes

Accepted answer
  1. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2022-07-28T22:16:14.093+00:00

    you don't explain your example very well. do you have typed classes defined for the table? also, how do you plan to read the typed list? generic<> are compile time, you you need to define a type as compile (you use codedom to generate the il code at runtime). if you have the classes defined you can use a mapper

     public List<dynamic> ReaderToList(DataReader render, string tableName) =>tableName switch  
     {  
              "TableName1" => reader.ToTableList<Table1Class>().Select(r => (dynamic) r).ToList(),  
              "TableName2" => reader.ToTableList<Table1Class>().Select(r => (dynamic) r).ToList(),  
    ...  
               _ => new List<dynamic>()  
    };  
    

1 additional answer

Sort by: Most helpful
  1. Karen Payne MVP 35,586 Reputation points Volunteer Moderator
    2022-07-27T21:39:54.843+00:00

    My advice is to not go in this direction and if you do pass in a fully qualified class name and work within the method which brings up a sore point of endless use of reflection. Here is a start

    /// <summary>  
    /// Given a fully qualified model/class name create a generic list  
    /// </summary>  
    /// <param name="className"></param>  
    public static void CreateGenericList(string className)  
    {  
        var type = Type.GetType(className, true);  
        var genericListType = typeof(List<>).MakeGenericType(type);  
        var genericList = Activator.CreateInstance(genericListType);  
    }  
    

    You are better off performing assertion and select a strong typed model and use code like this

    public static class Extensions  
    {  
        /// <summary>  
        /// Convert DataTable to List of T  
        /// </summary>  
        /// <typeparam name="TSource">Type to return from DataTable</typeparam>  
        /// <param name="table">DataTable</param>  
        /// <returns>List of <see cref="TSource"/>Expected type list</returns>  
        public static List<TSource> DataTableToList<TSource>(this DataTable table) where TSource : new()  
        {  
            List<TSource> list = new();  
      
            var typeProperties = typeof(TSource).GetProperties().Select(propertyInfo => new  
            {  
                PropertyInfo = propertyInfo,  
                Type = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType  
            }).ToList();  
      
            foreach (var row in table.Rows.Cast<DataRow>())  
            {  
      
                TSource current = new();  
      
                foreach (var typeProperty in typeProperties)  
                {  
                    object value = row[typeProperty.PropertyInfo.Name];  
                    object safeValue = value is null || DBNull.Value.Equals(value) ?   
                        null :   
                        Convert.ChangeType(value, typeProperty.Type!);  
      
                    typeProperty.PropertyInfo.SetValue(current, safeValue, null);  
                }  
      
                list.Add(current);  
      
            }  
      
            return list;  
        }  
    }  
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.