Я понимаю, что интерфейсы являются контрактами, и любые изменения (даже дополнения) взламывают любой зависимый код. Однако я, возможно, поклялся, что считал что-то некоторое время назад что одна из недавних версий.NET (3, 3.5??) добавил новый атрибут, который мог быть применен к новым интерфейсным участникам. Этот атрибут позволил дополнительным участникам управления версиями и/или создания. Это было бы что-то как:
interface ITest
{
void MethodOne();
[InterfaceVersion(2)]
void MethodTwo();
}
Я выглядел высоким и низким для этого, но просто, может казаться, не нахожу его. Я задаюсь вопросом, неправильно понял ли я просто то, что я думаю, что читал и нет такой вещи. У кого-то есть понимание?
Вы должны создать два интерфейса:
interface ITest
{
void MethodOne();
}
interface ITest2 : ITest
{
void MethodTwo();
}
Это также позволит понять, какая функциональность требует какой версии ваших интерфейсов, так что вам не придется проверять, реализует ли класс, реализующий интерфейс, только один или оба метода.
Недавно я оказался в ситуации, когда продиктованное отсутствие множественного наследования не позволяло мне преобразовывать существующий интерфейс в абстрактный класс, и обнаружил, что у меня есть расширяемое решение:
interface IFoo {
int RowCount();
}
static class _FooExtensions {
public static bool HasAnyRows (this IFoo foo) {
return foo.RowCount() > 0;
}
}
Таким образом, вы можете предоставить версию по умолчанию, если ваша аннотация метод может быть определен в терминах других функций.
Я не знаю таких атрибут, позволяющий частично реализовать реализацию интерфейса. Однако вы можете обойти это, используя абстрактный класс:
public abstract class Test
{
public abstract void MethodOne();
public virtual void MethodTwo() { }
}
Это позволит пользователю решить, хотят ли они переопределить MethodTwo при наследовании от Test, при этом принудительно переопределив MethodOne.
Возможно, вы читали что-то вроде
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
необязательной.
РЕДАКТИРОВАТЬ:
Я только что обнаружил, запустив код, что он действительно не делает реализацию MethodTwo
необязательной.
Я не видел такого атрибута, но думаю, это возможно. В этой статье в 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());
}
}
Возможно, вы думаете о новой функции "no pia" в C # 4? То есть мы позволяем вам «связывать» только те части интерфейса, которые вы фактически используете из PIA, а затем вы можете пропустить отправку PIA своим клиентам. Если вы затем сделаете это несколько раз в нескольких разных сборках, CLR выполнит работу по выяснению того, что все эти связанные частичные интерфейсы логически одного типа, и объединит их. Таким образом, вы можете передавать объекты, реализующие каждую разновидность интерфейса, из одной сборки в другую, и все это просто работает.Однако исходные интерфейсы , из которых создаются интерфейсы «no pia», должны быть одинаковыми.