Multiple implementation of an explicit interface

I have the following base interface

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

and two inheriting interfaces say

 public interface IAction1 : IBaseAction{} 

and

 public interface IAction2 : IBaseAction{} 

My problem is that I have a class that implements both, and I want to implement CanAct DIFFERENTLY.

 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(); 

Is there a clean enough way to do this?
(In addition, my interfaces have semantic meaning and at least three more functions, so it is possible that you selected the entire hierarchy, but I would like to copy the bool CanAct to each inheriting interface if this is the only solution (there are 4-6 of them))

+7
source share
7 answers

And what should the CLR do if someone calls ((IBaseAction)a1).CanSave() ? There can be only one implementation for IBaseAction.CanSave() . Therefore, I think that you cannot do this conceptually.

This is the fundamental problem of multiple inheritance, the diamond problem . The bottom line is this: if you click on it, your type hierarchy design will definitely be wrong. For example. in this particular case, you are better off with a role class model (also known as a role template).

+5
source

You cannot do what you describe. Imagine what happens if a client requests an IBaseAction interface. Which one needs to be returned?

It seems to me that each action should be performed by separate objects.

+5
source

You are trying to implement diamond inheritance using interfaces. For all reason, you are not allowed to implement several classes, primarily to avoid the inheritance of diamonds.

If you want to combine the two interfaces together as ComplexAction , you would do something like the following:

 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(); } } 

A ComplexAction is a composition with various IAct s. If you add a number to the interface name, the likelihood that you are doing something wrong is likely.

If instead you want to define other behavior based on an interface, that interface should define its method on its own.

 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; } } 

To avoid the problems of diamond inheritance, you must provide an implementation for ALL interfaces that define a specific method, so there is no ambiguity.

+3
source

I think you are trying to use inheritance for something that he should not have done. If you have a complex action, it consists of simpler actions, these are not several different actions at the same time.

Your ComplexAction must have Action1 and Action2 properties of types IAction1 and IAction2 , which are correctly implemented by CanSave() .

+1
source

It is not defined by IAction1 , but by IBaseAction .

The solution is to prevent the complex action from being implemented as (your current solution may break SRP)

0
source

You need to re-declare the IBaseAction members on the interfaces you want to defer, but then you also need to implement the IBaseAction tags implicitly or explicitly if there are no implicit member implementations (to make sure all interfaces are complete).

 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(); } } 

It may be unnecessary to point out that this project is weird to have elements with overlapping names that make you jump through hoops like this, but I decided that I would notice anyway.

You said you could not toss your current hierarchy, but you could reorganize it to avoid these frauds.

0
source

This does not work. You assume that IAction1 inherits IBaseAction, but that is not the case. Interfaces cannot inherit other interfaces. You can verify this using reflection to see the base layer IAction1. This will not be an IActionBase.

What do you say with your code: when a class implements IAction1, then IBaseAction is also required. C # will then help you by assuming that you are implementing IActionBase, simply by saying that you are implementing IAction1. Also, when using var of type IAction1, you can call participants from IBaseAction because it knows that it is implemented.

0
source

All Articles