Я верю, что Ɖiamond Ǥeeze ответ правильный.Я просто добавлю немного пояснений.
Вы не можете добавить украшение Contract.Requires
к методу в замкнутом построенном типе (например, IFetch<User>
).Вы должны добавить его к открытому построенному типу (IFetch<>
).Причиной этого является та же самая причина, по которой вы не можете добавить украшение Contract.Requires
к конкретному методу, который используется для реализации интерфейса: контракты кода предназначены для проверки во время компиляции, когда полный тип экземпляра объекта может бытьнеизвестно.
Предположим, это позволило вам заключить договор на реализацию конкретного метода.
public User Fetch(int id)
{
Contract.Requires (id != 0);,
return (User) Database.DoStuff (id);
}
Теперь предположим, что кто-то пытался использовать переменную типа интерфейса.
class DataDisplayer<T>
{
Label myLabel = new Label();
public void Display(IFetch<T> fetch, int id)
{
myLabel.Text = fetch.Fetch(id).ToString();
}
}
Допускает ли это нарушение договора или нет?Невозможно сказать, потому что мы не знаем, каким будет конкретный тип fetch
во время выполнения.
Заключение контракта для определенного закрытого составного типа, такого как IFetch<User>
, не решает эту проблему.Мы до сих пор не знаем, какой тип T в коде вызова.
Принцип подстановки Лискова, являющийся краеугольным камнем всего объектно-ориентированного программирования, означает, что мы никогда не можем предполагать что-либо о типе времени выполнения объекта, кроме того, что указывает тип переменной.А так как тип переменной может быть универсальным интерфейсом, контракты кода не могут наложить на вызывающего абонента какую-либо дополнительную нагрузку, чем в определении универсального интерфейса.
Следовательно, Contract.Requires
должно быть помещено в открытый составной тип,так что любой объект, реализующий интерфейс, будет иметь требование, и любой потенциальный вызов метода через переменную типа интерфейса может быть проверен на корректность по отношению к этому требованию.