C#功能参数实现抽象类和多个接口

Han*_*mpf 1 c# interface multiple-inheritance parameter-passing abstract

考虑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
Run Code Online (Sandbox Code Playgroud)

现在我有一个B类,它在构造函数中接受一个参数.该参数必须是以某种方式从A派生并实现接口I2的类,即它可以是类型A12或A22,但不是A11或A21.我该如何定义该参数?此外,我想稍后将参数存储为B中的属性(以供以后使用).

我无法将A重新定义为接口,因为它提供了许多虚拟方法.我也不能跳过树状继承方案,因为A1和A2提供了许多在别处使用的特定方法(不在B中).所以,我需要在B中处理的是来自A和I2的东西.

Eni*_*ity 5

这对你有用吗?

class B<T> where T : A, I2
{
    public B(T parameter)
    {
        this.Property = parameter;
    }

    public T Property { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 5

我该如何定义该参数?

基本上你不能.不在构造函数中.

你最接近的可能是创建一个返回B的静态泛型方法:

public static B CreateInstance<T>(T item) where T : A, I2
Run Code Online (Sandbox Code Playgroud)

您不能在构造函数中执行此操作,因为构造函数不能是通用的.

然而,然后如果你需要存储该值,则需要选择有类型的字段AI2,并投当您需要.

当然,您可以B根据Enigmativity的答案制作通用 - 但这可能会在其他地方产生其他影响.如果你想要一个非泛型的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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,这开始变得相当复杂.

或者,您可以跳过编译时检查,并在执行时检查:

public class B
{
    private readonly A item;

    public B(A item)
    {
        if (!(item is I2))
        {
            throw new ArgumentException("...");
        }
        this.item = item;
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然编译时安全性是一般较好,这可能是因为它不值得你需要在这种情况下要经过额外的铁圈.这实际上取决于你对这种类型做了什么.