我想创建一个泛型类,其中T参数可以是其他类型集合中的任何实例。 所以这段代码编译得很好:
public interface TestA { }
public interface TestB { }
public class Test<T> where T : TestA, TestB
{
}
然而,当我尝试像这样使用它时
var a = new Test<TestA>();
var b = new Test<TestB>();
我遇到两个编译错误:
错误1类型'TestA'不能用作类型参数'T' 泛型类型或方法'测试'。没有隐含的参考 从'TestA'转换为'TestB'。
错误2类型'TestB'不能用作类型参数'T' 泛型类型或方法'测试'。没有隐含的参考 从'TestB'转换为'TestA'。
我很困惑为什么这不起作用。我该如何解决这个问题?理想情况下,我希望TestA和TestB类没有关系(例如,它们之间没有继承)。
答案 0 :(得分:3)
类型必须遵循在泛型类型上定义的所有约束(AND,而不是OR)。
如果要同时允许TestS或Test,则应定义基本接口:
public interface TestBase { }
public interface TestA : TestBase { }
public interface TestB : TestBase { }
public class Test<T> where T : TestBase
{
}
答案 1 :(得分:1)
您指定该类必须实现这两个接口。所以你必须给它一个实现两个接口的类,而不仅仅是A或B
public class LikeThis : TestA, TestB
{
// have both A and B's properties, methods, etc.
}
var a = new Test<LikeThis>();
另一个选择是使TestA和TestB继承自基础接口
public interface IBaseInterface { }
public interface IInterfaceA { }
public interface IInterfaceB { }
public class Test<T> where T : IBaseInterface
{
}
var a = new Test<IBaseInterface>();
但很难说出你要在这里完成什么。 Test类可能会将对IBaseInterface的引用作为属性,但它不知道它是InterfaceA还是InterfaceB。
也许如果你告诉我们你想要实现的目标,我们可以建议一个更好的解决方案。
答案 2 :(得分:1)
对type参数的约束是连接(AND),因此在那里使用的任何类型都必须实现这两个接口。
正如已经提到的,一种方法是为两个接口创建一个超级接口,并将类型参数约束为(注意我添加了通常的接口前缀I
):
public interface IBase { }
public interface ITestA : TestBase { }
public interface ITestB : TestBase { }
public class Test<T> where T : IBase {
}
这样做的缺点是ITestA
或ITestB
的实施者不仅可以用作Test<T>
中的类型参数,还可以用作实现IBase
的任何其他类型。
另一个选择是提供一个不能从程序集外部继承的超类,并从中创建两个子类,每个所需的接口类型一个:
public interface ITestA { }
public interface ITestB { }
public abstract class Test<T> {
internal Test() { }
}
public class Test1<T> : Test<T> where T : ITestA { }
public class Test2<T> : Test<T> where T : ITestB { }
现在Test<T>
超类不能从程序集外部继承(它有一个internal
构造函数)。您的类(Test1<T>
和Test2<T>
)只使用超类的逻辑,并且每个类都使用一个所需的接口作为约束。客户端代码必须根据他们想要使用的接口约束来选择使用哪一个。
此外,如果您希望在Test<T>
内部使用接口中的公共代码,则应将其提取到超级接口并使您的超类受其约束,从而导致两种方法的混合:
public interface IBase { }
public interface ITestA : IBase { }
public interface ITestB : IBase { }
public abstract class Test<T> where T : IBase {
internal Test() { }
}
public class Test1<T> : Test<T> where T : ITestA { }
public class Test2<T> : Test<T> where T : ITestB { }