Явное ограничение реализации интерфейса - PullRequest
6 голосов
/ 07 декабря 2010

У меня очень простой сценарий: " человек " может быть " клиентом " или " сотрудником " компании.

" человек " может быть вызван по телефону методом " Call ".

В зависимости от того, какую роль " person " играет в контексте вызова , например, объявление о новом продукте или объявление об изменении в организации, мы должны либо использовать номер телефона, предоставленный для роли « customer », либо номер телефона, предоставленный для « employee » роль.

Вот итог ситуации:

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

Но этот код не компилируется и выдает ошибки:

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

Есть ли шанс, что этот сценарий может быть реализован в C # другим способом, или мне нужно будет найти другой дизайн?

Если да, то какие альтернативы вы предлагаете?

Заранее спасибо за помощь.

Ответы [ 6 ]

9 голосов
/ 07 декабря 2010

Ваша цель не имеет смысла.

Ни ICustomer, ни IEmployee не определяют Call() метод; они просто наследуют метод от одного и того же интерфейса. Ваш Both класс реализует один и тот же интерфейс дважды.
Любой возможный звонок Call всегда будет звонить IPerson.Call; нет никаких инструкций IL, которые бы конкретно вызывали ICustomer.Call или IEmployee.Call.

Вы можете решить эту проблему, явно переопределив Call в обоих дочерних интерфейсах, но я весьма рекомендую просто дать им разные имена.

1 голос
/ 21 июня 2012

Меня интересует ваш ввод с моим решением ...

Я часто использовал явную реализацию с композициями, когда я хочу, чтобы контроллер получил доступ к некоторым свойствам или методам моего класса, которые должны быть скрыты отрегулярное использование класса ...

Итак, чтобы иметь возможность иметь множественную реализацию 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 
    }
} 
1 голос
/ 09 мая 2012

Я столкнулся с этим сам.

Вы можете решить проблему, используя композицию:

interface IPerson
{
    void Call();
}

interface ICustomer : IPerson
{
}

interface IEmployee : IPerson
{
}

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

Выше предполагается, что Employee в классе Both является пользовательской реализацией IEmployee,и построен на основе объекта Both.

Но это зависит от того, как вы планировали использовать класс Both.
Если вы хотите использовать класс Both следующим образом:

((IEmployee)both).Call();

Тогда вместо этого вы можете использовать это:

both.Employee.Call();
1 голос
/ 07 декабря 2010

Помимо проблем, SLaks точно указал ...

Избавьтесь от IPerson и создайте IContactable с помощью метода Contact(), затем создайте два конкретных типа с именами Customer и Employee, которые реализуют IContactable. Тогда всякий раз, когда вам нужно связаться с кем-то, вы можете вызывать свой метод IContactable.Contact() по своему желанию, поскольку возможность установления контакта может расширяться, тогда как IPerson немного абстрактен.

0 голосов
/ 07 декабря 2010

Я не знаю, помогает это или нет, но вы могли бы сделать это.

//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 { } 
0 голосов
/ 07 декабря 2010

Вы не можете сделать это, потому что метод Call происходит из интерфейса IPerson в обоих случаях.Таким образом, вы пытаетесь определить метод Call два раза.Я предлагаю вам изменить интерфейс ICustomer и IEmployee на класс и определить метод Call в этом классе:

interface IPerson
{
    void Call();
}

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

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