Интерфейс C # - реализовать с другой подписью - PullRequest
3 голосов
/ 03 июня 2011

Полагаю, это тоже вопрос дизайна. Можно ли переопределить метод из интерфейса, если переопределенная подпись имеет другой тип подписи?

Например, допустим, я хочу два разных класса, которые должны иметь следующее:

 interface IProtocolClient
 {
    void connect(Type1 t1, Type2 t2, Type3 t3);
 }

Можно ли было бы задействовать интерфейс, но иметь другой набор параметров?

 class A : IProtocolClient {
   public void connect( Type1 t1, Type2 t2, Type3 t3 ) {}
 }

 class B : IProtocolClient {
   public void connect( Type1 t1, Type2 t2, Type3 t3, Type4 t4 ) {}
 }

Или мне следует подойти к этому, создав вместо этого базовый класс, а затем создать метод-оболочку в классе B, например:

 class B : IProtocolClient {
   public void connect( Type1 t1, Type2 t2, Type3 t3, Type4 t4)
   {
      // do what is needed with t4 to customize and then ...
      connect(t1,t2,t3);
   }

   public void connect( Type1 t1, Type2 t2, Type3 t3) {}
 }

Ответы [ 9 ]

3 голосов
/ 03 июня 2011

Нет, это не переопределение, это перегрузка. Перегрузка никогда не переопределяет, вам нужно будет реализовать оригинал, а затем предоставить перегрузку, которая вызывает реализацию интерфейса.

3 голосов
/ 03 июня 2011

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

3 голосов
/ 03 июня 2011

Ваш последний вариант - единственный, который мог бы работать (так как это единственный вариант, который правильно реализует интерфейс в обоих классах).

Помните, однако, что любой, кто получает доступ к классу через интерфейс, будет иметь доступ только к методу connect(Type1 t1, Type2 t2, Type3 t3), который полностью аннулирует тот факт, что вы предоставляете другой (если только люди не могут получить доступ к типу напрямую).

1 голос
/ 03 июня 2011

Я бы сказал, что либо перейдите к варианту 2, либо измените интерфейс, чтобы принимать список типов.

1 голос
/ 03 июня 2011

Если вы реализуете интерфейс, вы ДОЛЖНЫ включать любые методы, свойства и т. Д. В этом суть интерфейсов: они являются контрактами кода.Это не мешает вам перегружать методы разными сигнатурами параметров.Но если вам не нужно реализовывать указанный метод, то вам, вероятно, вообще не нужен интерфейс.

0 голосов
/ 03 июня 2011

Если вы передаете все параметры как объект, вы можете получить класс параметров и затем привести его в реализованный метод.

    interface IProtocolClient
    {
        void connect(ParamType p);
    }

    class ParamType
    {
        public Type1 t1 { get; set; }
        public Type2 t2 { get; set; }
        public Type3 t3 { get; set; }
    }

=>

    class A : IProtocolClient
    {
        public void connect(ParamType p)
        {
            //do something with p.t1, p.t2, p.t3
        }
    }

    class B : IProtocolClient
    {
        public void connect(ParamType p)
        {
            var p2 = p as DerivedParamType;
            if (p2 == null)
                throw new ApplicationException("p must be of type DerivedParamType");
            //do something with p2.t1, p2.t2, p2.t3, p2.t4
        }
    }

    class DerivedParamType : ParamType
    {
        public Type4 t4 { get; set; }
    }

hth

0 голосов
/ 03 июня 2011

Если бы все типы были одинаковыми или имели общий базовый класс или интерфейс, такой как IConnectable, вы могли бы использовать ключевое слово params:

http://msdn.microsoft.com/en-us/library/w5zay9db.aspx

0 голосов
/ 03 июня 2011

Если вы хотите, чтобы все классы, которые реализуют IProtocolClient, знали обе подписи, то добавьте подпись перегрузки в прокси

public interface IProtocolClient
 {
    void connect(Type1 t1, Type2 t2, Type3 t3);
    void connect( Type1 t1, Type2 t2, Type3 t3, Type4 t4)
 }

Если вы хотите скрыть эту подпись в некоторых реализациях, вы можете реализовать ее явно

    class A : IProtocolClient {
       public void connect( Type1 t1, Type2 t2, Type3 t3 ) {}
       void  IProtocolClient.connect(Type1 t1, Type2 t2, Type3 t3, Type4 t4){
        throw new NotImplementedException();
       }     
 }

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

0 голосов
/ 03 июня 2011

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

Однако, я думаю, что приведенная ниже реализация довольно чиста.

public interface ITestClass
{
    void Test(Type a, Type b);
}

public class TestClass : ITestClass
{

    //implement the interface here
    public void Test(Type a, Type b)
    {
        Test(a, b);
    }

    //you actual implementation here
    public void Test(Type a, Type b, Type c = null)
    {
        //implementation
    }
}

Обновление Если вы идете со списком вещей, тогда эта реализация предпочтительна:

    public void Test(params Type[] parameters)
    {
        //sample usage
        Type one, two, three, four;
        Test(one, two);
        Test(one, two, three, four);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...