我有以下基本界面
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个))
答案 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
类型的属性IAction1
和IAction2
。
答案 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调用成员,因为它知道它已实现。