Question

I have a very simple scenario : a "person" can be a "customer" or an "employee" of a company.

A "person" can be called by phone with the "Call" method.

Depending on which role the "person" plays in the context of the call, e.g. the announcement of a new product or the announcement of a change in organization, we should either use the phone number provided for the "customer" role or the one provided for the "employee" role.

Here is a sum-up of the situation :

interface IPerson
{
    void Call();
}

interface ICustomer : IPerson
{
}

interface IEmployee : IPerson
{
}

class Both : ICustomer, IEmployee
{
    void ICustomer.Call()
    {
        // Call to external phone number
    }

    void IEmployee.Call()
    {
        // Call to internal phone number
    }
}

But this code doe not compile and produces the errors :

error CS0539: 'ICustomer.Call' in explicit interface declaration is not a member of interface
error CS0539: 'IEmployee.Call' in explicit interface declaration is not a member of interface
error CS0535: 'Both' does not implement interface member 'IPerson.Call()'

Does this scenario has any chance to be implementable in C# in a different way or will I have to find another design ?

If so what alternatives do you propose ?

Thanks in advance for your help.

Was it helpful?

Solution

Your objective does not make sense.

Neither ICustomer nor IEmployee define a Call() method; they just inherit the method from the same interface. Your Both class implements the same interface twice.
Any possible Call call will always call IPerson.Call; there are no IL instructions that will specifically call ICustomer.Call or IEmployee.Call.

You may be able to solve this by explicitly redefining Call in both child interfaces, but I highly recommend that you just give them different names.

OTHER TIPS

Aside from the issues SLaks accurately pointed out...

Get rid of IPerson and create IContactable with a method of Contact(), then Create two concrete types called Customer and Employee that implement IContactable. Then whenever you need to contact someone you can call your IContactable.Contact() method as desired since being able to make contact could expand, whereas IPerson is a bit abstract.

I ran into this myself.

You can solve the problem by using composition:

interface IPerson
{
    void Call();
}

interface ICustomer : IPerson
{
}

interface IEmployee : IPerson
{
}

class Both
{
    public ICustomer Customer { get; }
    public IEmployee Employee { get; }
}

The above assumes that the Employee in the Both class is a custom implementation of IEmployee, and is constructed based on a Both object.

But it depends on how you were planning to use the Both class.
If you wanted to use the Both class like this:

((IEmployee)both).Call();

Then instead you can use this:

both.Employee.Call();

I'm interested on your input with my solution...

I used explicit implementation a lot with compositions when I want a controller to access some properties or methods on my class that should be hidden from a regular usage of the class...

So, to be able to have multiple implementation of IPerson, in this example, I would use generic, to be able to split the IPerson interface from a customer to an employee

interface IPerson<T>
{
    void Call();
}

interface ICustomer : IPerson<ICustomer>
{
}

interface IEmployee : IPerson<IEmployee>
{
}

class Both : ICustomer, IEmployee
{
    void IPerson<ICustomer>.Call()
    {
        // Call to external phone number 
    }

    void IPerson<IEmployee>.Call()
    {
        // Call to internal phone number 
    }
} 

You can't do this because the Call method comes from the IPerson interface in the two cases. So you try to define the Call method two times. I suggest you to change your ICustomer and IEmployee interface into class and to define the Call method in this class :

interface IPerson
{
    void Call();
}

class Customer : IPerson
{
    public void Call()
    {
    }
}

class Employee : IPerson
{
    public void Call()
    {
    }
}

I dont know if this helps or not, but you could get it a shot.

//ran in linqpad c# program mode, you'll need to provide an entry point.....
void Main()
{
    IPerson x;
    x = new Both(new Employee());
    x.call(); //outputs "Emplyee"
    x = new Both(new Customer());
    x.call(); //outputs "Customer"
}

class Customer :  ICustomer
{
    public void call() {"Customer".Dump();}
}
class Employee :  IEmployee
{
    public void call() {"Employee".Dump();}
}
class Both : IPerson
{
     private IPerson Person { get; set; }
     public Both(IPerson person)
     {
         this.Person = person;
     }
     public void call()
     {
        Person.call();
     }
} 
interface IPerson { void call(); }  
interface ICustomer : IPerson { } 
interface IEmployee : IPerson { } 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top