0

我有一个名为 SCO 的基类,它继承了许多类。我最初只是想对集合进行排序,但根据一些建议,听起来我可以用一种方法对集合进行实例化和排序。

我有这个所有基类都继承的构造函数:

public SCO(SPListItem item, List<Vote> votes)
{
    UpVotes = voteMeta.UpVotes;
    DownVotes = voteMeta.DownVotes;
    VoteTotal = UpVotes - DownVotes;
    HotScore = Calculation.HotScore(Convert.ToInt32(UpVotes), Convert.ToInt32(DownVotes), Convert.ToDateTime(item["Created"]));
}

这就是我卡住的地方。我无法实例化<T>.

public static List<T> SortedCollection<T>(SPListItemCollection items, ListSortType sortType, List<Vote> votes) where T : SCO
{
    var returnlist = new List<T>();
    for (int i = 0; i < items.Count; i++) { returnlist.Add(new T(items[i], votes)); }
    switch (sortType)
    {
        // Sort List based on passed ENUM
    }
    return returnlist;
}

如果我可以用一种方法完成所有这些,我就可以避免一些昂贵的铸造和拳击。

4

3 回答 3

3

泛型中唯一允许的约束是new(),它仅在存在不带任何参数的构造函数时才有效。

我有这个所有基类都继承的构造函数:

问题是这是不可强制执行的。子类可以(并且应该)自由定义自己的构造函数,只要它们链接到这个构造函数。子类可以自由使用实例化该类所需的任何构造机制。

您可以通过反射和Activator.CreateInstance解决此问题,这将允许您使用参数构造对象。然而,这相当“丑陋”(尽管考虑到使用new() 约束仍然调用 Activator.CreateInstance ,并不丑陋):

Type genericType = typeof(T);
for (int i = 0; i < items.Count; i++) 
{ 
     returnlist.Add((T)Activator.CreateInstance(genericType, new object[] {items[i], votes})); 
}
于 2012-08-24T23:49:20.590 回答
2

这里缺少的是比您实例化T对象的方法更通用的东西:

new T(items[i], votes)

编译器不能保证每个 type 都存在这个构造函数T。您可以做的是让函数接受一些工厂方法类型的附加参数Func<SPListItem, IList<Vote>, T>,以便可以重写上面的内容:

returnlist.Add(factory(items[i], votes))

或者,您可以改为实现一个工厂,该类有效地包含代码中派生自 的每种类型的此实例化逻辑SCO,例如:

class SCOFactory
{
    public T Create<T>(SPListItem item, IList<Vote> votes) where T : SCO
    {
        // Do your instantiation here.
    }
}

你经常看到这种情况(它通常被称为“工厂模式”);它作为一种方法(通常是一个巨大的声明)可能有点丑陋switch,但至少它在一个地方包含了丑陋,并允许您编写诸如问题中的函数之类的函数,而无需添加另一个参数并最终弄乱一个你的项目中有很多代码。

一个普遍的警告(当然要持保留态度):过度泛化您的代码最终会导致令人头疼的问题,而不会产生太多切实的好处。在继续之前先问问自己,以这种通用方式编写此代码是否真的对您有益;如果是这样,上述任何一个建议都可能是一个不错的起点。如果不是,请考虑采用一种更简单的方法,这种方法在理论上可能不太灵活,但在实践中更容易使用。

于 2012-08-24T23:52:30.010 回答
0

需要在构造函数中传递这些值吗?

您可以在类型上创建那些可设置的属性,然后调用默认构造函数,在创建对象后,只需在...之后设置属性

于 2012-08-25T00:03:43.410 回答