C # Интерфейсы с дополнительными методами - PullRequest
37 голосов
/ 04 марта 2010

Я понимаю, что интерфейсы являются контрактами и любые изменения (даже дополнения) нарушают любой зависимый код. Тем не менее, я мог поклясться, что недавно прочитал, что в одной из последних версий .NET (3, 3.5 ??) добавлен новый атрибут, который можно применить к новым членам интерфейса. Этот атрибут позволял управлять версиями и / или делать членов необязательными. Это было бы что-то вроде:

interface ITest
{
    void MethodOne();

    [InterfaceVersion(2)]
    void MethodTwo();
}

Я искал все это, но просто не могу его найти. Я задаюсь вопросом, не понял ли я просто то, что, как мне кажется, я прочитал, и такого не существует. У кого-нибудь есть понимание?

Ответы [ 7 ]

45 голосов
/ 04 марта 2010

Вы должны создать два интерфейса:

interface ITest
{
    void MethodOne();
}

interface ITest2 : ITest
{
    void MethodTwo();
}

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

10 голосов
/ 04 марта 2010

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

Короче говоря, C # оснащен языковыми функциями, которые позволяют производным классам развиваться и сохранять совместимость. В этом примере показано чисто базовое отношение к производному, но на самом деле базовый реализует интерфейс, необходимый для версии. Наличие одного интерфейса требует другого (предыдущая версия) интерфейса в сочетании с этим методом, также весьма полезно.

Пример создания интерфейса, который требует другого:

public interface IMyInterface
{
  void FirstMethod();
}

public interface IMySecondInterface : IMyInterface
{
  void SecondMethod();
}

Пример использования наследования для поддержания совместимости:

public class MyBase 
{
   public virtual string Meth1() 
   {
      return "MyBase-Meth1";
   }
   public virtual string Meth2() 
   {
      return "MyBase-Meth2";
   }
   public virtual string Meth3() 
   {
      return "MyBase-Meth3";
   }
}

class MyDerived : MyBase 
{
   // Overrides the virtual method Meth1 using the override keyword:
   public override string Meth1() 
   {
      return "MyDerived-Meth1";
   }
   // Explicitly hide the virtual method Meth2 using the new
   // keyword:
   public new string Meth2() 
   {
      return "MyDerived-Meth2";
   }
   // Because no keyword is specified in the following declaration
   // a warning will be issued to alert the programmer that 
   // the method hides the inherited member MyBase.Meth3():
   public string Meth3() 
   {
      return "MyDerived-Meth3";
   }

   public static void Main() 
   {
      MyDerived mD = new MyDerived();
      MyBase mB = (MyBase) mD;

      System.Console.WriteLine(mB.Meth1());
      System.Console.WriteLine(mB.Meth2());
      System.Console.WriteLine(mB.Meth3());
   }
}
6 голосов
/ 04 марта 2010

Возможно, вы думаете о новой функции "без пиа" в C # 4? То есть мы разрешаем вам «связывать» только те части интерфейса, которые вы фактически используете от PIA, а затем вы можете пропустить доставку PIA своим клиентам. Если вы затем сделаете это несколько раз в нескольких разных сборках, CLR выполнит работу по выяснению того, что все эти объединенные частичные интерфейсы логически одинакового типа, и объединит их. Таким образом, вы можете передавать объекты, реализующие каждый вариант интерфейса, из одной сборки в другую, и все это просто работает. Однако оригинальные интерфейсы, из которых создаются интерфейсы "no pia", должны быть одинаковыми.

5 голосов
/ 04 марта 2010

В .NET Framework такого атрибута нет.

4 голосов
/ 04 марта 2010

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

public abstract class Test
{
     public abstract void MethodOne();
     public virtual void MethodTwo() { }
}

Это позволит пользователю решить, хотят ли они переопределить MethodTwo при наследовании из Test, при этом принудительно переопределяя MethodOne.

2 голосов
/ 04 марта 2010

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

    interface IFoo {
            int RowCount();
    }

    static class _FooExtensions {
            public static bool HasAnyRows (this IFoo foo) {
                    return foo.RowCount() > 0;
            }
    }

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

1 голос
/ 04 марта 2010

Возможно, вы прочитали что-то вроде

 interface ITest
{
    void MethodOne();

    [InterfaceVersion(2)]
    void MethodTwo();
}



[AttributeUsage(AttributeTargets.All)]
public class InterfaceVersion : System.Attribute
{
    public readonly int N;

    public InterfaceVersion(int n) 
    {
        this.N = n;
    }
}

Но я не думаю, что это может сделать реализацию MethodTwo необязательной.

EDIT:

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

...