Обладает ли следующий интерфейс допустимым контрактом:
public interface IContainer<T>
{
IEnumerable<T> Items { get; }
int Count { get; }
}
Ну понятно, Count я могу определить через Items, а вот Items как бы я определить не могу. Значит контракт не допустим? Где вообще,уважаемые, можно про такие вещи почитать?
Спасибо.
А>Ну понятно, Count я могу определить через Items, а вот Items как бы я определить не могу. Значит контракт не допустим? Где вообще,уважаемые, можно про такие вещи почитать? А>Спасибо.
На лице непонимание "контракта" и "интерфейса".
1) Интерфейс класса то что предоставляет класс потребителю с точки зрения языка, то есть в C# интерфейс — набор свойств и методов с именем и типами.
2) Контракт — дополнительные условия, налагаемые на интерфейс. например то что Count всегда положителен, а Items не возвращает null.
Здравствуйте, Аноним, Вы писали:
А>Ну понятно, Count я могу определить через Items,
Не всегда. IEnumerable не имеет св-ва Count.Если наследующая IEnumerable коллекция не реализует Count, то без непосредственного итерирования по всем элементам узнать Count не удасться.
>а вот Items как бы я определить не могу.
Это почему?
>Значит контракт не допустим?
Если компилятор пропускает, значит допустим.
Кодом людям нужно помогать!
Re: Контракт интерфейса
От:
Аноним
Дата:
29.04.12 05:40
Оценка:
Здравствуйте, Аноним, Вы писали:
Это особенности языка. например из такого интерфейса
public interface Locker {
void Lock();
void Unlock();
}
совершенно не очевидно можно ли lock-ать вложено или нет.
в таких случаях можно использовать комментарии
Если мало комментарием то кидай исключения и используй тесты.
А>совершенно не очевидно можно ли lock-ать вложено или нет. А>в таких случаях можно использовать комментарии А>Если мало комментарием то кидай исключения и используй тесты.
В принципе, в тех же дот-нетах, контракты можно определить и более формально:
[ContractClass(typeof(LockerContracts))] // указываем контрактpublic interface Locker {
// Без дополнительного публичного свойства никак,
// вызывающий код должен понимать, какие контракты налагаются каждым
// методом и должен иметь возможность проверить выполнимость предусловияbool Locked {get;}
void Lock();
void Unlock();
}
// В .net-е контракты указываются не с помощью атрибутов (они слишком слабовыразительны для этого)
// а с помощью отдельных классов, реализующих требуемый интерфейсinternal abstract class LockerContracts : Locker
{
public bool Locked {get {throw new NotImplementedException;}}
public void Lock() {
// Все, теперь клиенты будут знать, что дважды локать нельзя
// в противном случае - это баг со всеми вытекающими (ассертом или
// исключением в рантайме)
Contract.Requires(!Locked, "We can't acquire lock twice");
}
public void Unlock() {
// Здесь картина аналогична, попытка заанлокать незалоченное приведет к беде
Contract.Requires(Locked, "We can't release free lock!");
}
}
Теперь можно на это дело натравить статический анализатор, который еще и во время компиляции (точнее посткомпиляции) сможет отловить проблемы.
А>Ну понятно, Count я могу определить через Items, а вот Items как бы я определить не могу. Значит контракт не допустим? Где вообще,уважаемые, можно про такие вещи почитать? А>Спасибо.
Ну а в данном конкретном случае мне не понятно, зачем вообще городить огород, и не воспользоваться нужным типом коллекции.
Например, начиная с .net 4.5 нас осчастливят наконец-то интерфейсом IReadonlyList:
public interface IReadOnlyList<out T> : IEnumerable<T>, IEnumerable
{
int Count { get; }
T this[int index] { get; }
}
Еще можно просто изменить тип возвращаемого значения на ICollection<T>, или на ReadonlyCollection<T>, если знаете, что он точно не будет изменяться.
З.Ы. Существующие типы сами по себе являются отличным выразительным средством задания контракта и прибегать к другим уловкам стоит тогда, когда этой выразительности недостаточно.
З.Ы.Ы. Да и вообще, мне не совсем понятно, о каком контракте здесь может идти речь, кроме как что свойство Count должно возвращать количество элементов в свойстве Items. Если это действительно так нужно, то в терминах Code Contracts это можно выразить, но вопрос: нужно ли?
Здравствуйте, artelk, Вы писали:
A>Здравствуйте, SergeyT., Вы писали:
ST>>начиная с .net 4.5 нас осчастливят наконец-то интерфейсом IReadonlyList: A>Вау! Неужто дождались?!
Хотя не понятно, почему нас не осчастливят IReadOnlyCollection-ом, все же IReadonlyList содержит индексатор, что налагает серьезные ограничения на реализующую его коллекцию.
Здравствуйте, SergeyT., Вы писали:
ST>Здравствуйте, artelk, Вы писали:
A>>Здравствуйте, SergeyT., Вы писали:
ST>>>начиная с .net 4.5 нас осчастливят наконец-то интерфейсом IReadonlyList: A>>Вау! Неужто дождались?!
ST>Хотя не понятно, почему нас не осчастливят IReadOnlyCollection-ом, все же IReadonlyList содержит индексатор, что налагает серьезные ограничения на реализующую его коллекцию.
Так ведь нужно же что-то оставить, что можно будет добавить в .net 6.0 и 7.0
Или просто не догадались . Интересно, есть ли шанс, что они таки воткнут IReadOnlyCollection между IReadonlyList и IEnumerable?
public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
{
int Count { get; }
}
public interface IReadOnlyList<out T> : IReadOnlyCollection<T>
{
T this[int index] { get; }
}
Может было задето чье-то эстетическое чувство при виде интерефейсов из одного метода?
Или может побоялись полностью взорвать мозг разработчикам, которые будут ожидать, что IReadOnlyCollection — это интерфейс класса ReadOnlyCollection, который, сейчас реализует IList ( ), а в .net 4.5 будет реализовывать IReadOnlyList...
Здравствуйте, artelk, Вы писали:
A>Здравствуйте, SergeyT., Вы писали:
ST>>Хотя не понятно, почему нас не осчастливят IReadOnlyCollection-ом, все же IReadonlyList содержит индексатор, что налагает серьезные ограничения на реализующую его коллекцию.
Вот что подумалось: у интерфейса IEnumerable<T> есть метод-расширение Count(). Если посмотреть его реализацию, то видно, что для объектов, реализующих ICollection<T>, он обращается к их свойству Count, вместо прохождения по всем элементам. Т.е. IReadOnlyCollection<T>, возможно, избыточен. С другой стороны, если у нас есть некий метод SomeMethod(IEnumerable<T>), в его теле мы не должны полагаться на то, что метод Count() будет выполняться эффективно и для такого случая лучше иметь специальный интерфейс IReadOnlyCollection<T>/ICountableEnumerable<T>/etc.
A>Интересно, есть ли шанс, что они таки воткнут IReadOnlyCollection между IReadonlyList и IEnumerable?
Запостил это в качестве идеи сюда: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2845869-ireadonlycollection-t-
Вдруг поможет.