我试图在添加到列表时通过其构造函数创建一个T类型的新对象。
我得到一个编译错误:错误消息是:
'T':创建变量实例时不能提供参数
但是我的类确实有构造函数参数!我该怎么做呢?
public static string GetAllItems<T>(...) where T : new()
{
...
List<T> tabListItems = new List<T>();
foreach (ListItem listItem in listCollection)
{
tabListItems.Add(new T(listItem)); // error here.
}
...
}
使用c# 11中的静态抽象接口方法特性,可以使用工厂模式构建一个变通方案。例如:
public interface IFactory<TSelf> where TSelf : IFactory<TSelf> {
static abstract TSelf New(int i, string s);
}
public struct Foo : IFactory<Foo> {
public static Foo New(int i, string s) {
return new Foo(i, s);
}
public readonly int I;
public readonly string S;
public Foo(int i, string s) {
I = i;
S = s;
}
}
public static class Maker {
public static T Make<T>(int i, string s) where T : IFactory<T> {
return T.New(i, s);
}
}
这种方法的一个限制是它只能用于您拥有的类,因为您需要在目标类上实现特定的工厂接口。
对象初始化器
如果你的带形参的构造函数除了设置属性之外没有做任何事情,你可以在c# 3中使用对象初始化器而不是调用构造函数来做这件事(这是不可能的,正如前面提到的):
public static string GetAllItems<T>(...) where T : new()
{
...
List<T> tabListItems = new List<T>();
foreach (ListItem listItem in listCollection)
{
tabListItems.Add(new T() { YourPropertyName = listItem } ); // Now using object initializer
}
...
}
使用它,您也可以将任何构造函数逻辑放在默认(空)构造函数中。
Activator.CreateInstance ()
或者,你可以像这样调用Activator.CreateInstance():
public static string GetAllItems<T>(...) where T : new()
{
...
List<T> tabListItems = new List<T>();
foreach (ListItem listItem in listCollection)
{
object[] args = new object[] { listItem };
tabListItems.Add((T)Activator.CreateInstance(typeof(T), args)); // Now using Activator.CreateInstance
}
...
}
注意Activator。CreateInstance可能有一些性能开销,如果执行速度是最优先考虑的,并且另一个选项对您来说是可维护的,那么您可能希望避免这些开销。
使用c# 11中的静态抽象接口方法特性,可以使用工厂模式构建一个变通方案。例如:
public interface IFactory<TSelf> where TSelf : IFactory<TSelf> {
static abstract TSelf New(int i, string s);
}
public struct Foo : IFactory<Foo> {
public static Foo New(int i, string s) {
return new Foo(i, s);
}
public readonly int I;
public readonly string S;
public Foo(int i, string s) {
I = i;
S = s;
}
}
public static class Maker {
public static T Make<T>(int i, string s) where T : IFactory<T> {
return T.New(i, s);
}
}
这种方法的一个限制是它只能用于您拥有的类,因为您需要在目标类上实现特定的工厂接口。
补充业绩资料
使用Jeroen van Langen的表达式方法(见上文)对数据库访问和数据模型类填充进行性能测试,并直接实例化数据模型类。
结论:该法表达速度快。
结果:
数据模型类的直接实例:
纪录:3558秒:1.2746019
实例的方法读取列表的类型参数:
记录:3558秒:0.4878858
表达式方法的代码示例:
var list = ReadList<DataModel>(SQLStatement, Connection);
方法ReadList:
注意:所有数据模型类都有一个参数类型为SQLDataReader的构造函数
public static List<pDataModel> ReadList<pDataModel>(string pSQLStatement, SqlConnection pConnection) where pDataModel : new()
{
// constructor of data model
var lType = typeof(pDataModel);
var lParameters = new Type[] { typeof(SqlDataReader) };
var lDataModelConstructor = CreateConstructor(lType, lParameters);
// read data
List<pDataModel> lDataList = new List<pDataModel>();
using (pConnection)
{
SqlCommand lCommand;
lCommand = new SqlCommand(pSQLStatement, pConnection);
pConnection.Open();
SqlDataReader lReader = lCommand.ExecuteReader();
if (lReader.HasRows)
{
while (lReader.Read())
{
pDataModel lDataItem = (pDataModel)lDataModelConstructor(lReader);
lDataList.Add(lDataItem);
}
}
lReader.Close();
pConnection.Close();
}
return lDataList;
}
直接实例化的代码示例:
List<DataModel> list= new List<DataModel>();
using (connection)
{
SqlCommand command;
command = new SqlCommand(SQLStatement, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
list.Add(new DataModel(reader));
}
}
reader.Close();
connection.Close();
}