Под контравариацией и ковариацией подразумевается использование одного и того же типа? - PullRequest
0 голосов
/ 08 октября 2018

Я совсем запутался.Я наткнулся на правила подписи (на которые ссылается также Б.Лисков в своей работе), в которых говорится:

Противопоставление аргументов. m1 и m2 имеют одинаковое количество аргументов.Если список типов аргументов m1 равен a , а список m2 равен b , то ∀i. a i <<em> b i // означает, что a является подтипом b .

Из другого учебного материала:

Чтобы тип функции DY → CY был подтипом (т. Е. Заменяемым) DX → CX, мы должен быть ковариантным в типе результата, но противоречивым в типе аргумента!

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

Другими словами, так как c # не допускает противоречивость аргументов, значит ли это, что мой код никогда не совместим с LSP?Когда я прочитал, что LSP требует, чтобы аргументы были контравариантными.

class Person
{
}
class Employee: Person
{
}

class PersonRegister
{
   GetJobTitle(Employee e) {return e.JobTitle;}
}

class DeriverRegister: PersonRegister
{
  GetJobTitle(Person p)  //contravariance, using less derived type, cannot be done in C#
}

Как это могло бы работать, если, например, у менее производного типа нет требуемого поля, в этом примере JobTitle?Это собственность Сотрудника, но обязательно Лица.

1 Ответ

0 голосов
/ 08 октября 2018
class Person
{
}
class Employee: Person
{
}

class PersonRegister
{
   GetJobTitle(Employee e) {return e.JobTitle;}
}

class DeriverRegister: PersonRegister
{
  GetJobTitle(Person p)  //contravariance, using less derived type, cannot be done in C#
}

Вы правы.Если вы хотите, чтобы GetJobTitle в DervierRegister считался override из GetJobTitle из PersonRegister, он должен использовать точно тех же типов.Вам должно быть разрешено создать этот метод как написано, но он shadows тот из PersonRegister и не считается переопределением.Таким образом, вы можете написать выше, но

var e = new Employee();
PersonRegister pr = new DervierRegister();
pr.GetJobTitle(e);

вызовет метод из PersonRegister.

означает ли это, что мой код никогда не будет совместим с LSP?

В той степени, в которой вы не можете использовать ковариацию и контравариантность обычно , да.Однако для общих интерфейсов и делегатов была добавлена ​​поддержка в C # 4.0.А также, как уже говорилось, при формальном обращении каждый тип считается подтипом самого себя, поэтому фразы типа " a является подтипом a " верны для всех типов а .

...