2012-01-12 3 views
8

Возможно, я ошибаюсь в кодовых контрактах, но вот моя ситуация.Кодовые контракты и проблемы наследования, что происходит?

У меня есть следующий код:

interface IFetch<T> // defined in another DLL 
{ 
    T Fetch(int id); 
} 

interface IUserFetch : IFetch<User> 
{ 
    IEnumerable<User> GetUsersLoggedIn(); 
} 

class UserFetch : IUserFetch 
{ 
    public User Fetch(int id) 
    { 
     return (User) Database.DoStuff (id); 
    } 

    public IEnumerable<User> GetUsersLoggedIn() 
    { 
     return (IEnumerable<User>) Database.DoMoreStuff(); 
    } 
} 

Я пытаюсь добавить относительно простой договор: Contract.Requires (id != 0);, и я хочу это подтверждено на Fetch. Когда я добавляю его непосредственно в Fetch, я получаю предупреждение, что Method Fetch(int id) implements interface 3rdParty.IFetch<User> and thus cannot add Requires.

Я создал класс абстрактных кодовых контрактов, реализующий IFetch, и указал его в/из UserFetch, используя атрибуты соответственно. Я все еще получаю сообщение об ошибке CodeContracts: The class 'FetchUserContracts' is supposed to be a contract class for '3rdParty.IFetch<User>', but that type does not point back to this class. Однако, поскольку 3rdParty.IFetch является универсальным типом, я не думаю, что смогу когда-либо поставить на него кодовый контракт.

Была ли проблема выяснена, и если да, то как ее решить?

+0

Возможный дубликат: http://stackoverflow.com/questions/3414586 –

+0

@RobertHarvey: Я в основном возьму это, за исключением того, что моя проблема, похоже, больше связана с генериками –

ответ

5

Я считаю, что ответ Ɖ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 должен быть помещен в открытый сконструированный тип, так что любой объект, реализующий интерфейс, будет иметь требование, и любой потенциальный вызов метода через переменную типа интерфейса можно проверить на корректность с учетом к этому требованию.

10

Вы должны создать абстрактный класс для реализации контракта, например:

[ContractClassFor(typeof(IFetch<>))] 
public abstract class ContractClassForIFetch<T> : IFetch<T> 
{ 
    public T Fetch(int id) 
    { 
     Contract.Requires(id != 0); 
     return default(T); 
    } 
} 

И добавьте следующий ContractClass атрибут БДИ:

[ContractClass(typeof(ContractClassForIFetch<>))] 
public interface IFetch 
{ 
    T Fetch(int id); 
} 
+0

См. Также этот [связанный Q/A] (https: //stackoverflow.com/questions/3414586/) – orad

Смежные вопросы