我正在尝试在添加到列表时通过其构造函数创建类型为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.
}
...
}
13 回答
这不适用于您的情况 . 您只能指定它具有空构造函数的约束:
你可以做的是通过定义这个接口来使用属性注入:
然后你可以改变你的方法:
另一种选择是JaredPar描述的
Func
方法 .在.Net 3.5中,您可以使用激活器类:
如果您可以访问您将要使用的类,则可以使用我使用的这种方法 .
创建一个具有替代创建者的界面:
使用空创建者创建类并实现此方法:
现在使用您的通用方法:
如果您没有访问权限,请包装目标类:
我有时使用类似于使用属性注入的答案的方法,但保持代码更清洁 . 它不包含具有一组属性的基类/接口,而只包含一个(虚拟)Initialize()方法,该方法充当“穷人的构造函数” . 然后你可以让每个类像构造函数那样处理它自己的初始化,这也增加了一种处理继承链的方便方法 .
如果经常发现自己处于需要链中的每个类初始化其唯一属性的情况,然后调用其父级的Initialize()方法,而该方法又初始化父级的唯一属性,依此类推 . 这在具有不同类但具有类似层次结构时尤其有用,例如映射到/来自DTO的业务对象:s .
使用通用字典进行初始化的示例:
这有点肮脏,当我说肮脏时我可能意味着反感,但假设你可以用空构造函数提供参数化类型,那么:
将有效地允许您使用参数从参数化类型构造对象 . 在这种情况下,我假设我想要的构造函数有一个类型为
object
的参数 . 我们使用约束允许的空构造函数创建T的虚拟实例,然后使用反射来获取其他构造函数 .我相信您必须使用where语句约束T,以仅允许具有新构造函数的对象 .
现在它接受任何包括没有它的物体的东西 .
很老的问题,但新答案;-)
The ExpressionTree version :(我认为紧固和最干净的解决方案)
就像Welly Tambunan说的那样,"we could also use expression tree to build the object"
这将为给定的类型/参数生成“构造函数”(函数) . 它返回一个委托并接受参数类型作为对象数组 .
这里是:
Example MyClass:
Usage:
另一个例子:将类型作为数组传递
DebugView of Expression
This is equivalent to the code that is generated:
Small downside
所有valuetypes参数在像对象数组一样传递时都会被装箱 .
Simple performance test:
结果:
使用
Expressions
是/ - 8 times faster 比调用ConstructorInfo
和/ - 20 times faster 比使用Activator
Object initializer
如果带有参数的构造函数除了设置属性之外没有做任何事情,你可以使用object initializer在C#3或更好的情况下执行此操作,而不是调用构造函数(这是不可能的,如上所述):
使用它,您始终可以将任何构造函数逻辑放在默认(空)构造函数中 .
Activator.CreateInstance()
或者,您可以像这样调用Activator.CreateInstance():
请注意,Activator.CreateInstance可以包含一些performance overhead,如果执行速度是最高优先级而另一个选项可以维护,则可能需要避免 .
如果您只想使用构造函数参数初始化成员字段或属性,则在C#> = 3中,您可以更轻松地执行此操作:
这与Garry Shutler所说的相同,但我想提出一个附加说明 .
当然,除了设置字段值之外,您还可以使用属性技巧来执行更多操作 . 属性“set()”可以触发设置其相关字段所需的任何处理以及对象本身的任何其他需要,包括检查是否在使用对象之前进行完全初始化,模拟完整的构造(是的,这是一个丑陋的解决方法,但它克服了M $的新()限制) .
我不能保证它是一个计划的洞还是偶然的副作用,但它确实有效 .
M $人们如何为语言添加新功能并且似乎没有进行完整的副作用分析,这非常有趣 . 整个通用的东西都是这个的好证据......
您需要添加T:new(),让编译器知道T保证提供默认构造函数 .
既然没有人愿意发布“反思”答案(我个人认为是最好的答案),这里有:
编辑:由于.NET 3.5的Activator.CreateInstance,这个答案已被弃用,但它在旧的.NET版本中仍然有用 .
我发现我收到错误“在创建类型参数T的实例时无法提供参数”所以我需要这样做:
要在函数中创建泛型类型的实例,必须使用“new”标志约束它 .
但是,只有在想要调用没有参数的构造函数时才会有效 . 不是这里的情况 . 相反,您必须提供另一个参数,该参数允许基于参数创建对象 . 最简单的是一个功能 .
然后你就可以这样称呼它