考虑C#中的以下结构:
interface I1
interface I2
abstract class A
- class A1 : A
- class A11 : A1, I1
- class A12 : A1, I2
- class A2 : A
- class A21 : A2, I1
- class A22 : A2, I2
现在我有一个B类,它在构造函数中接受一个参数。该参数必须是以某种方式从A派生并实现接口I2的类,即它可以是类型A12或A22,但不是A11或A21。我该如何定义该参数?此外,我想稍后将参数存储为B中的属性(以供以后使用)。
我无法将A重新定义为接口,因为它提供了许多虚拟方法。我也不能跳过树状继承方案,因为A1和A2提供了许多在别处使用的特定方法(不在B中)。所以,我需要在B中处理的是来自A和I2的东西。
答案 0 :(得分:5)
这对你有用吗?
class B<T> where T : A, I2
{
public B(T parameter)
{
this.Property = parameter;
}
public T Property { get; private set; }
}
答案 1 :(得分:5)
基本上,你不能。不在构造函数中。如何定义该参数?
你最接近的是创建一个返回B的静态泛型方法:
public static B CreateInstance<T>(T item) where T : A, I2
您不能在构造函数中执行此操作,因为构造函数不能是通用的。
但是,如果您需要存储该值,则需要选择包含A
或I2
类型的字段,并在需要时进行投射
当然,根据Enigmativity的回答,您可以使B
通用 - 但这可能会在其他地方产生其他影响。如果您想要非通用B
,则可能同时拥有两者:
public abstract class B
{
// Common operations which don't depend on the constructor parameter
}
public class B<T> : B where T : A, I2
{
public B(T item)
{
}
}
当然,这开始变得相当复杂。
或者,您可以跳过编译时检查,并在执行时检查:
public class B
{
private readonly A item;
public B(A item)
{
if (!(item is I2))
{
throw new ArgumentException("...");
}
this.item = item;
}
}
虽然编译时安全性通常是优选的,但它可能在这种情况下你不需要经历额外的箍。这实际上取决于你对这种类型做了什么。
答案 2 :(得分:0)
您是否需要创建A1,A2,A12,A22类的实例,如果没有,那么您可以将它们抽象化并仅限制实现它们的类的构造函数参数
class B
{
public B(A11 a12)
{
}
public B(A22 a12)
{
}
}