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.
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.
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
}
}
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();
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 { }
精彩评论