Принцип подстановки Лискова Инвариантность [закрыто]
Может ли кто-нибудь объяснить мне, почему этот код не работает? Как это связано с правилом LSP? Что в этом контексте означает инвариантность?
Пример взят из Адаптивного кода из книги C #:
class Program
{
static void Main(string[] args)
{
IDictionary<A, A> dict1 = new Dictionary<B,B>();
IDictionary<B,B> dict2 = new Dictionary<A, A>();
}
}
public class A { }
public class B: A { }
Сообщение об ошибке
Ошибка CS0266 Невозможно неявно преобразовать тип System.Collections.Generic.Dictionary<LSP.core.B, LSP.core.B> в System.Collections.Generic.IDictionary<LSP.core.A, LSP.core.A>'. Существует явное преобразование (отсутствует ли приведение?)
Ошибка CS0266 Невозможно неявно преобразовать тип System.Collections.Generic.Dictionary<LSP.core.A, LSP.core.A> в System.Collections.Generic.IDictionary<LSP.core.B, LSP.core.B>'. Существует явное преобразование (вам не хватает приведения?)
2 ответа
Простой пример:
class A { }
class B : A { }
class C : A { }
// Imagine this was allowed:
var dict1 = new Dictionary<B, B>();
IDictionary<A, A> dict2 = dict1;
// Then you did this:
var c = new C();
dict2[c] = c;
// And finally tried to do this:
B b = dict1.Keys.First(); // Breaks type safety, because First() returns a C instance
Это потому, что IDictionary - это
generic
класс.
Возьмем следующий пример:
public class A { }
public class B: A { }
B является подклассом A, поэтому это разрешено.
A varName = new B();
но когда вы используете
varName
в коде вы можете получить доступ только к свойствам класса A
Но
List<B>
не является подклассом
List<A>
, Несмотря на то
B
является подклассом.
Компилятор не проверяет тип универсального параметра на наследование и считает их разными типами.
следующее не допускается
List<A> listName = new List<B>();
какой идентификатор разрешен для использования правила LSP для заполнения списка
List<A> listName = new List<A>();
ListName.Add(new B());
Но когда вы получаете доступ
ListName[0]
компилятор рассматривает полученный объект как тип
A
объект.