多个显式接口实现

时间:2011-06-19 21:43:48

标签: c# inheritance interface

我有以下基本界面

public interface IBaseAction
{
   bool CanAct(...)
}

和两个继承接口说

public interface IAction1 : IBaseAction{}

public interface IAction2 : IBaseAction{}

我的问题是,我有一个实现两者的类,我想实现不同的CanAct。

public class ComplexAction : IAction1, IAction2
{
   bool IAction1.CanAct(...){} //doesn't compile as CanAct is not a member of IAction1!!
}

ComplexAction c=new ComplexAction();
var a1 = (IAction1)c;
var a2 = (IAction2)c;
a1.CanSave(); //THESE TWO CALLS SHOULD BE IMPLEMENTED DIFFERENTLY
a2.CanSave();

有一个相当干净的方法吗?
 (另外,我的界面具有语义和至少三个功能,因此抛弃整个层次结构是不可能的,但是我愿意将bool CanAct复制到每个继承接口,如果这是唯一的解决方案(其中有4-6个))

7 个答案:

答案 0 :(得分:5)

如果有人拨打((IBaseAction)a1).CanSave(),CLR应该做什么? IBaseAction.CanSave()可能只有一个实现。所以我认为你不能从概念上做到这一点。

这是多重继承的基本问题,称为the diamond problem。底线是:如果你点击它,你的类型层次结构设计肯定是错误的。 例如。在这种特殊情况下,你最好使用Role class model(也称为角色模式)。

答案 1 :(得分:5)

你无法做你所描述的。试想一下,如果客户端请求IBaseAction接口会发生什么。应归还哪一个?

我觉得每个动作都应该由不同的对象实现。

答案 2 :(得分:3)

您正在尝试使用Interfaces实现钻石继承。你不允许首先实现多个类的全部原因是为了避免钻石继承。

如果要将两个接口组合在一起作为ComplexAction,您可以执行以下操作:

interface IAct
{
    bool CanAct();
}

class Act1 : IAct
{
    public bool CanAct()
    {
        return true;
    }
}

class Act2 : IAct
{
    public bool CanAct()
    {
        return false;
    }
}

class ComplexAction : IAct
{
    private Act1 action1;
    private Act2 action2;

    public ComplexAction(Act1 action1, Act2 action2)
    {
        this.action1 = action1;
        this.action2 = action2;
    }

    public bool CanAct()
    {
        return action1.CanAct() && action2.CanAct();
    }
}

ComplexAction是不同IAct的组合。如果你在接口名称上附加一个数字,那么你做错了很可能很高。

相反,如果您希望基于接口定义不同的行为,那么接口必须自己定义它的方法。

interface IAct1
{
    bool CanAct();
}

interface IAct2
{
    bool CanAct();
}

class SometimesAct1SometimesAct2 : IAct, IAct1, IAct2
{
    bool IAct1.CanAct()
    {
        return false;
    }

    bool IAct2.CanAct()
    {
        return true;
    }

    public bool CanAct()
    {
        Console.WriteLine("Called on IAct or SometimesAct1SometimesAct2");
        return false;
    }
}

为避免钻石继承问题,您必须为定义特定方法的所有接口提供实现,因此不存在歧义。

答案 3 :(得分:1)

我认为你正试图将继承用于不应该做的事情。如果你有一个复杂的动作,它是组成更简单的动作,它不是同时有多个不同的动作。

您的ComplexAction应该包含已正确实施Action1的{​​{1}}和Action2类型的属性IAction1IAction2

答案 4 :(得分:0)

它不是由IAction1定义的,而是由IBaseAction定义的。

解决方案是不要让复杂的操作同时实现(您当前的解决方案可能会破坏SRP)

答案 5 :(得分:0)

你需要在需要延迟的接口上重新声明IBaseAction的成员,但是如果没有隐式实现,你还需要隐式或显式地实现IBaseAction的成员成员(以确保满足所有接口)。

interface IBase {
    void Act();
}

interface IAction1 : IBase {
    void Act();
}

interface IAction2 : IBase {
    void Act();
}

class MyClass : IAction1, IAction2 {
    public void Act() {
        Console.WriteLine( "satisfies IBase.Act()" );
    }
    void IAction1.Act() {
        Console.WriteLine( "IAction1.Act()" );
    }
    void IAction2.Act() {
        Console.WriteLine( "IAction2.Act()" );
    }

    static void Main( string[] args ) {
        MyClass cls = new MyClass();
        cls.Act();
        IAction1 a = cls;
        a.Act();
        IAction2 b = cls;
        b.Act();
        Console.ReadKey();
    }
}

指出这种设计很难有重叠命名的成员,这会迫使你像这样跳过箍,但我想我还是会注意到它。

你确实说过你不能抛弃你当前的等级制度,但也有可能重构它以避免这些恶作剧。

答案 6 :(得分:0)

这不行。您假设IAction1继承了IBaseAction,但事实并非如此。接口不能继承其他接口。您可以使用反射来查看IAction1的基类。它不会是IActionBase。

您对代码的评价是:当一个类实现IAction1时,它也需要实现IBaseAction。 C#将通过假设您通过告诉它实现IAction1来实现IActionBase来帮助您。此外,当使用IAction1类型的变量时,您可以从IBaseAction调用成员,因为它知道它已实现。