我试图在添加到列表时通过其构造函数创建一个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.
}
...
}
这在你的情况下行不通。你只能指定一个构造函数为空的约束:
public static string GetAllItems<T>(...) where T: new()
你可以通过定义这个接口来使用属性注入:
public interface ITakesAListItem
{
ListItem Item { set; }
}
然后你可以改变你的方法如下:
public static string GetAllItems<T>(...) where T : ITakesAListItem, new()
{
...
List<T> tabListItems = new List<T>();
foreach (ListItem listItem in listCollection)
{
tabListItems.Add(new T() { Item = listItem });
}
...
}
另一种替代方法是JaredPar描述的Func方法。
使用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);
}
}
这种方法的一个限制是它只能用于您拥有的类,因为您需要在目标类上实现特定的工厂接口。
我有时使用类似于使用属性注入的答案的方法,但使代码更简洁。
它没有一个带有一组属性的基类/接口,只包含一个(虚拟的)Initialize()方法,充当“穷人的构造函数”。
然后,您可以让每个类像构造函数一样处理自己的初始化,这也为处理继承链增加了一种方便的方式。
If经常发现自己处于这样的情况:我希望链中的每个类初始化其唯一属性,然后调用其父类的initialize()方法,该方法反过来初始化父类的唯一属性,以此类推。当具有不同的类,但具有相似的层次结构时,这尤其有用,例如映射到DTO:s的业务对象。
使用普通Dictionary进行初始化的示例:
void Main()
{
var values = new Dictionary<string, int> { { "BaseValue", 1 }, { "DerivedValue", 2 } };
Console.WriteLine(CreateObject<Base>(values).ToString());
Console.WriteLine(CreateObject<Derived>(values).ToString());
}
public T CreateObject<T>(IDictionary<string, int> values)
where T : Base, new()
{
var obj = new T();
obj.Initialize(values);
return obj;
}
public class Base
{
public int BaseValue { get; set; }
public virtual void Initialize(IDictionary<string, int> values)
{
BaseValue = values["BaseValue"];
}
public override string ToString()
{
return "BaseValue = " + BaseValue;
}
}
public class Derived : Base
{
public int DerivedValue { get; set; }
public override void Initialize(IDictionary<string, int> values)
{
base.Initialize(values);
DerivedValue = values["DerivedValue"];
}
public override string ToString()
{
return base.ToString() + ", DerivedValue = " + DerivedValue;
}
}