繁体   English   中英

多个显式接口实现

[英]Multiple explicit interface implementation

我有以下基本界面

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个))

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

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

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

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

您正在尝试使用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;
    }
}

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

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

ComplexAction应该有属性Action1Action2类型, IAction1IAction2已正确实施CanSave()

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

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

您需要在需要延迟的接口上重新声明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();
    }
}

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

你确实说过你不能抛弃当前的层次结构,但有可能重构它以避免这些恶作剧。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM