使用任意对象类型来解析 MySql 查询(学习 C# 反射)

Use an arbitrary object type to parse a MySql query (learning C# Reflection)

我正在尝试更好地理解 C# 上的泛型和反射。作为练习,我正在执行 MySql 查询并尝试将其结果解析为预定义对象:

//FOR TABLE A 
public class ObjectType1
    {
        public int id { get; set; }
        public String name { get; set; }
    }

 //FOR TABLE B
public class ObjectType2
    {
        public int id { get; set; }
        public timestamp expirationDate  { get; set; }    
    }

 //FOR TABLE C 
public class ObjectType3
    {
        public int id { get; set; }
        public BigDecimal price  { get; set; }
    
    }

我的目标是这样的:

List<ObjectType1> listObjectsA =  selectAndCast(tableNameA, ObjectType1)
List<ObjectType2> listObjectsB =  selectAndCast(tableNameB, ObjectType2)
List<ObjectType3> listObjectsC =  selectAndCast(tableNameC, ObjectType3)

我的问题是,如何将所需的对象类型指定为参数? (已经在 S.O 处检查了类似的问题,但出现了编译错误)。

问题/工作代码的答案:

感谢@JosephDaSilva 的更正

public List<T> selectAndCast<T>(string connStr, String query, int argTimeoutSecs) where T : new()
        {

            MySqlConnection conn = new MySqlConnection(connStr);

            MySqlDataReader rdr = null;

            List<T> listaSalida = new List<T>();


            try
            {
                conn.Open();

                MySqlCommand cmd = new MySqlCommand(query, conn);

                if (argTimeoutSecs != -1)
                {
                    cmd.CommandTimeout = argTimeoutSecs;
                }

                rdr = cmd.ExecuteReader();

                //  Create a dictionary that contains each column name and a consecutive number. That number will be later  used to locate the column by its name.

                Dictionary<String, int> dictionaryColumnNameVsIndex = new Dictionary<String, int>();

                for (int i = 0; i < rdr.FieldCount; i++)
                {
                    String nombreColumna = rdr.GetName(i);
                    dictionaryColumnNameVsIndex.Add(nombreColumna, i);
                }

                
                PropertyInfo[] properties = typeof(T).GetProperties();

                T destinationObject;

                while (rdr.Read())
                {

                    //  For each row obtained from the query execution, create a new instance of the Object

                    destinationObject = new T();


                    for (int i = 0; i < rdr.FieldCount; i++)
                    {

                        foreach (PropertyInfo property in properties)
                        {

                            //  Check if the destination object contains a property with the same name.

                            if (dictionaryColumnNameVsIndex.ContainsKey(property.Name))
                            {

                                //  If it does, assign the value to said property.

                                PropertyInfo propertyToBeChanged = destinationObject.GetType().GetProperty(property.Name);

                                String newValue = rdr[dictionaryColumnNameVsIndex[property.Name]].ToString();

                                propertyToBeChanged.SetValue(destinationObject, newValue);
                            }
                        }
                    }

                    //  After all rows have been processed, return the object list
                    listaSalida.Add(destinationObject);

                }

                return listaSalida;

            }

            catch (Exception ex)
            {

                Console.WriteLine("Error when trying to SELECT: " + ex.ToString()); 
                return null;

            }
            finally
            {
                if (rdr != null)
                {
                    rdr.Close();
                    conn.Close();
                }
            }

        }

selectAndCast 方法中使用类型参数 T 作为对象的类型。由于您需要创建类型的实例,因此使用 new() 约束类型参数,这要求类型具有无参数构造函数(所有对象类型都有一个,因为没有显式构造函数)。所以 selectAndCast 方法应该声明为:

public List<T> selectAndCast<T>(string tableName) where T : new() {
   // ...
}

要创建 List<T> 的实例,请使用:

List<T> listaSalida = new List<T>();

要创建类型 T 的实例(由于 new() 约束而有效):

T destinationObject = new T();

获取类型 T 的属性(这也应该移到读取循环之外,因为它每次总是 return 相同的属性列表):

PropertyInfo[] properties = typeof(T).GetProperties();

泛型方法可以这样调用:

List<ObjectType1> listObjectsA = selectAndCast<ObjectType1>(tableNameA);