【问题标题】:C# Function parameter implementing abstract class and multiple interfacesC#函数参数实现抽象类和多个接口
【发布时间】:2014-02-04 09:53:49
【问题描述】:

考虑 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 的东西。

【问题讨论】:

  • 不确定这是否有帮助,但不要将 A 作为抽象类,而是考虑将其作为接口并将其方法实现为扩展方法。
  • @Raphaël Althaus:因为我需要访问 B 类中 A 的属性和方法。
  • 你想如何使用传递的对象?作为 A 类还是作为 I2 接口?
  • @Alexandr Mihalciuc:两者同时进行。否则很容易实现。

标签: c# interface parameter-passing multiple-inheritance abstract


【解决方案1】:

如何定义该参数?

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

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

public static B CreateInstance<T>(T item) where T : A, I2

你不能在构造函数中这样做,因为构造函数不能是泛型的。

但是,如果您需要存储该值,则需要选择AI2 类型的字段,并在需要时进行转换。

当然,您可以根据 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;
    }
}

虽然编译时安全性通常更可取,但可能在这种情况下,您需要经历额外的麻烦并不值得。这实际上取决于您对类型所做的工作。

【讨论】:

  • 您可以定义一个通用类 - 就像 Enigmativity 的答案。
  • @Ian:是的,我正在更新我的答案以包括这种可能性,以及它周围的其他选项。使类型泛型是强制类的所有用户的选择,而不仅仅是那些构造实例的用户 - 这是一个可能超出合理范围的负担。
  • 没错——我曾经尝试建立一个类库,它使用了很多基于其他泛型的泛型类。我很快了解到,实际上泛型可能很痛苦。你也可以投票:P
  • 我尝试了不同的解决方案,在我看来,使用运行时检查是我将使用的方式。它不是很漂亮,但似乎最省事。谢谢。
【解决方案2】:

这对你有用吗?

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

    public T Property { get; private set; }
}

【讨论】:

  • 我试过了,但它似乎会导致 WinForms 出现问题。实际上,在真正的问题中,B 类是一个 Form(忘了提)。我最终得到了一个像“partial class B : Form where T : A, I2”这样的结构,它似乎在某个地方杀死了设计师。
  • @HansD.Ampf - 是的,作为 Windows 窗体会杀死它。实际上,它并没有直接杀死它。它仍然可以工作,但你会发现,你会失去设计师的支持。
【解决方案3】:

您是否需要创建 A1、A2、A12、A22 类的实例,如果不需要,则可以将它们抽象化,并将构造函数参数限制为仅实现它们的类

class B
    {
        public B(A11 a12)
        {

        }

        public B(A22 a12)
        {

        }   

    }

【讨论】:

  • 那是我的第一次尝试。然而,这意味着失去相当多的灵活性,因为(在真正的问题中)不仅仅是 A12 和 A22。而且我不想每次在 A 下面的树中添加另一个项目时都重写 B。
猜你喜欢
  • 2012-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-17
  • 1970-01-01
  • 2012-09-02
  • 2014-02-05
  • 2011-02-11
相关资源
最近更新 更多