如何将包含某些属性的custom-class类型的未知对象列表传递给方法?

我正在创建一个databasehelper类,其中包含访问SQLCE数据库的方法。 我想使用相同的方法使用包含与不同表中的字段匹配的属性的不同类来读取行。 要使用的类是在运行时确定的,我想将包含类中对象的列表传递给方法,并获取属性名并使用它们来读取数据库。 会非常方便,因为我可以将它用于我的所有(SQLCE-)数据库。

(我更新了错误的代码以便在这里提供解决方案)

#region ReadData ///---------------------------------------------------------------------- ///  /// Reads datarows from database and adds them to list. ///  /// List containing objects with properties. /// Table in database. /// Substring of SQL-statement that follows 'WHERE'. /// Connectionstring. /// true if successfull ///---------------------------------------------------------------------- public static bool ReadData(List data, string table, string search, string connect) where T : class, new() { // Return if input id missing if (data == null || table == "" || connect == "") return false; // retrieve properties from Data PropertyInfo[] propinf = typeof(T).GetProperties(); // Create string with SQL-statement string fields = ""; // retrieve fields from propinf foreach (PropertyInfo p in propinf) { fields += fields == "" ? p.Name : ", " + p.Name; } // create SQL SELECT statement with properties and search string sql = "SELECT " + fields + " FROM " + table; sql += search == "" ? "" : " WHERE " + search; // Instantiate and open database SqlCeConnection cn = new SqlCeConnection(connect); if (cn.State == ConnectionState.Closed) cn.Open(); data.Clear(); // just in case try { SqlCeCommand cmd = new SqlCeCommand(sql, cn); cmd.CommandType = CommandType.Text; SqlCeResultSet rs = cmd.ExecuteResultSet(ResultSetOptions.Scrollable); if (rs.HasRows) // Only if database is not empty { while (rs.Read()) // read database { // instantiate single item of list Data var dataitem = new T(); int ordinal = 0; foreach (PropertyInfo p in propinf) { // read database and PropertyInfo singlepropinf = typeof(T).GetProperty(p.Name); ordinal = rs.GetOrdinal(p.Name); singlepropinf.SetValue(dataitem, rs.GetValue(ordinal), null); // fill data item } data.Add(dataitem); // and add it to data. } } else { MessageBox.Show("No records matching '" + search + "'!"); return false; } } catch (SqlCeException sqlexception) { MessageBox.Show(sqlexception.Message, "SQL-error.", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } catch (Exception ex) { MessageBox.Show(ex.Message, "Error.", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } finally { cn.Close(); } return true; } #endregion 

我有两个问题:

1)如何通过未知类型的列表? 到目前为止我发现的答案并没有帮助我解决这个问题。

2)如何实例化一个未知类型的对象(在编译时),以便将它添加到List而不会导致编译错误?

非常感谢!

1:未知类型的列表可以是非通用IListArrayListList

2: Activator.CreateInstance(type)

或者,看一下编写generics方法,理想情况如下:

 ReadData(List data, ...) where T : class, new() 

并使用new T()来创建新项目,并使用typeof(T)来讨论Type 。 使用通用方法,调用者通常隐式地提供T。 请注意,您的示例中不需要ref

下面是对代码的更新。 它接近最终,并已在各种不同的情况下进行测试。 理想情况下,使用reflection的迭代必须被性能较低的东西所取代,但只要数据库操作更耗时,我想它在现实生活中并不重要。 我已经很满意了。

  #region Read(Like)Data public static int ReadData(List data, string table, T search, string connect) where T : class, new() { return BaseRead(data, table, search, connect, "="); } public static int ReadLikeData(List data, string table, T search, string connect) where T : class, new() { return BaseRead(data, table, search, connect, "LIKE"); } ///---------------------------------------------------------------------- ///  /// Reads datarows from database and adds them to list containing objects of type T. /// Note that the properties of T should match the fields of the database table. ///  /// List containing objects of type T with properties matching fields in table. /// Table in database. /// Object of type T with (some) properties containing search constraints, /// others should be null. Unused DateTime should be 1800-01-01. /// Connectionstring. /// -1 if exception was thrown or the number of records (objects of type T) otherwise ///---------------------------------------------------------------------- private static int BaseRead(List data, string table, T search, string connect, string comparer) where T : class, new() { // Abort if insufficient arguments if (data == null || table == "" || connect == "") return 0; // Make sure List data is empty data.Clear(); // Retrieve properties from object of type T PropertyInfo[] propinfs = typeof(T).GetProperties(); // ----------------------------------------- // Create string that contains SQL-statement // ----------------------------------------- string fields = ""; string wherestr = ""; // Retrieve fields from propinf foreach (PropertyInfo p in propinfs) { fields += fields == "" ? p.Name : ", " + p.Name; dynamic propvalue = p.GetValue(search, null); // Solutions for properties of type DateTime long dateticks = 0; DateTime dt = new DateTime(); Type type = propvalue != null ? propvalue.GetType() : null; if (propvalue != null && propvalue.GetType() == dt.GetType()) { dt = propvalue; dateticks = dt.Ticks; } // DateTime 1800-01-01 equals null (hey, it's better than nothing...) if (propvalue != null && dt != DateTimeNull) wherestr += wherestr == "" ? p.Name + " " + comparer + " @" + p.Name.ToLower() : " AND " + p.Name + " " + comparer + " @" + p.Name.ToLower(); } // Create SQL SELECT statement with properties and search string sql = "SELECT " + fields + " FROM " + table; sql += wherestr == "" ? "" : " WHERE " + wherestr; // ------------------- // Database operations // ------------------- SqlCeConnection cn = new SqlCeConnection(connect); if (cn.State == ConnectionState.Closed) cn.Open(); try { SqlCeCommand cmd = new SqlCeCommand(sql, cn); cmd.CommandType = CommandType.Text; // Add propertyvalues to WHERE-statement using reflection foreach (PropertyInfo p in propinfs) { dynamic propvalue = p.GetValue(search, null); // Except for DateTime values 1800-01-01 (defined as null) if (propvalue != null && !(propvalue.GetType() is DateTime && propvalue != DateTimeNull)) { if (comparer == "LIKE") propvalue = "%" + propvalue + "%"; cmd.Parameters.AddWithValue("@" + p.Name.ToLower(), propvalue); } } SqlCeResultSet rs = cmd.ExecuteResultSet(ResultSetOptions.Scrollable); if (rs.HasRows) // Only if database is not empty { while (rs.Read()) // Read next row in database { // Instantiate single item of List data var dataitem = new T(); // Object to put the field-values in foreach (PropertyInfo p in propinfs) { // Read database fields using reflection PropertyInfo singlepropinf = typeof(T).GetProperty(p.Name); int ordinal = rs.GetOrdinal(p.Name); dynamic result = rs.GetValue(ordinal); // Conversion to null in case field is DBNull if (result is DBNull) { if (singlepropinf.PropertyType.Equals(typeof(DateTime))) { singlepropinf.SetValue(dataitem, DateTimeNull, null); // Fill data item with datetimenull } else { singlepropinf.SetValue(dataitem, null, null); // Fill data item with null } } else { singlepropinf.SetValue(dataitem, result, null); // Or fill data item with value } } data.Add(dataitem); // And add the record to List data. } } else { //MessageBox.Show("No records matching '" + wherestr + "'!"); return 0; } } catch (SqlCeException sqlexception) { MessageBox.Show(sqlexception.Message, "SQL-error.", MessageBoxButtons.OK, MessageBoxIcon.Error); return -1; } catch (Exception ex) { MessageBox.Show(ex.Message, "Error.", MessageBoxButtons.OK, MessageBoxIcon.Error); return -1; } finally { cn.Close(); } // Return number of objects (should equal number of retrieved records) return data.Count(); } #endregion