简体   繁体   English

显式接口实现限制

[英]Explicit interface implementation limitation

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 , eg 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 ? 这种情况是否有机会以不同的方式在C#中实现,还是我必须找到另一种设计?

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; ICustomerIEmployee都没有定义Call()方法; they just inherit the method from the same interface. 他们只是从同一个接口继承该方法。 Your Both class implements the same interface twice. 您的Both类两次实现相同的接口。
Any possible Call call will always call IPerson.Call ; 任何可能的Call呼叫将始终呼叫IPerson.Call ; there are no IL instructions that will specifically call ICustomer.Call or IEmployee.Call . 没有专门调用ICustomer.CallIEmployee.Call IL指令。

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. 您可以通过在两个子接口中显式重新定义Call来解决此问题,但我强烈建议您只是给它们不同的名称。

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. 以上假设Both类中的Employee是IEmployee的自定义实现,并且是基于Both对象构造的。

But it depends on how you were planning to use the Both class. 但这取决于你打算如何使用Both类。
If you wanted to use the Both class like this: 如果你想像这样使用Both类:

((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 因此,为了能够多次实现IPerson,在本例中,我将使用泛型,以便能够将IPerson接口从客户拆分为员工

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... 除了SLaks准确指出的问题......

Get rid of IPerson and create IContactable with a method of Contact() , then Create two concrete types called Customer and Employee that implement IContactable . 摆脱IPerson并使用Contact()方法创建IContactable ,然后创建两个实现IContactable称为CustomerEmployee具体类型。 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. 然后,当你需要联系某人时,你可以根据需要调用你的IContactable.Contact()方法,因为能够进行联系可以扩展,而IPerson有点抽象。

You can't do this because the Call method comes from the IPerson interface in the two cases. 你不能这样做,因为Call方法来自两种情况下的IPerson接口。 So you try to define the Call method two times. 因此,您尝试两次定义Call方法。 I suggest you to change your ICustomer and IEmployee interface into class and to define the Call method in this class : 我建议您将ICustomer和IEmployee接口更改为类,并在此类中定义Call方法:

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

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

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