9

我有一个接口ISnack,当它由一个类实现时,它应该有一个默认的无参数构造函数。基本上是这样的:

public interface ISnack<T> where T : new()
{

}

<T> where T : new()只是用来强制执行无参数构造函数。

然后我会以这种方式实现接口:

public class Cutlet : ISnack<Cutlet>
{

}

这是可行的,它只是确保Cutlet类具有无参数的构造函数。

现在我有一个抽象基类Kitchen

public abstract class Kitchen<T> where T : ISnack
{

}

要求是Kitchen应该有约束 whereT应该是ISnack. 但这不会起作用,因为不存在ISnack,而只有ISnack<T>.

如果我试过这个

public abstract class Kitchen<T> where T : ISnack<T>
{

}

它不会编译 ( 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'ISnack<T>') 并且在我的上下文中也没有意义。

如果我可以强制ISnacks 具有无参数构造函数而不受T类型参数的约束,那么TinKitchen<T>很容易成为ISnack. 怎么办?

4

3 回答 3

14

除非您添加约束,否则您不能;通用约束是累积的,所以为了让编译器满意,你必须拥有:

public abstract class Kitchen<T> where T : ISnack<T>, new()

如果没问题,那就这样做。如果它不好,那么你将不得不: new从原件中删除它,并且没有它。这并不像听起来那么糟糕,但这意味着您将验证下推到执行而不是编译。但是:Activator.CreateInstance<T>()无论如何,仍然可以满足您的需求-即使没有new()约束。所以你可以替换:

T newObj = new T(); // validated by the compiler

和:

T newObj = Activator.CreateInstance<T>(); // not validated until executed

删除约束时一个方便的技巧是:添加一个单元/集成测试,通过反射找到候选类型,并验证缺少的约束作为测试套件的一部分

于 2012-10-09T11:41:59.603 回答
3

您可以使用第二个通用参数:

abstact class Kitchen<T, S> 
    where T : ISnack<S> 
    where S : new()
....

这将解决您的问题。

向类添加第二个参数也可能导致我在 .NET 2.0 可用后遇到的一些问题。一些复杂的情况可能需要向类添加比您喜欢的更多的通用参数。(SpecificType)base.MyTypeTProperty通常我通过添加更多的直接强制转换(如)来分解通用链。评论:我试着稍后再找一个样本

于 2012-10-09T12:14:11.683 回答
1

只需将约束再次添加到 T

public abstract class Kitchen<T> where T : ISnack<T>, new()   {      }
于 2012-10-09T11:42:40.037 回答