Язык программирования C#9 и платформа .NET5
}Console.ReadLine();Обратите внимание, что когда применяется ключевое слово
, отпадает необходимость в наличии логикиas, т.к. если ссылка не являетсяtry/catch, то известно, что вызов происходит для действительной ссылки на интерфейс.nullПолучение ссылок на интерфейсы: ключевое слово is (обновление в версии 7.0)
Проверить, реализован ли нужный интерфейс, можно также с помощью ключевого слова
(о котором впервые упоминалось в главе 6). Если интересующий объект не совместим с указанным интерфейсом, тогда возвращается значениеis. В случае предоставления в операторе имени переменной ей назначается надлежащий тип, что устраняет необходимость в проверке типа и выполнении приведения. Ниже показан обновленный предыдущий пример:falseConsole.WriteLine("***** Fun with Interfaces *****\n");...if(hex2 is IPointy itfPt3){Console.WriteLine("Points: {0}", itfPt3.Points);}else{Console.WriteLine("OOPS! Not pointy...");}Console.ReadLine();Стандартные реализации (нововведение в версии 8.0)
Как упоминалось ранее, в версии C# 8.0 методы и свойства интерфейса могут иметь стандартные реализации. Добавьте к проекту новый интерфейс по имени
, предназначенный для представления многоугольника заданной формы. Вот код интерфейса:IRegularPointynamespace CustomInterfaces{interface IRegularPointy : IPointy{int SideLength { get; set; }int NumberOfSides { get; set; }int Perimeter => SideLength * NumberOfSides;}}Добавьте к проекту новый файл класса по имени
, унаследуйте класс от базового классаSquare.csи реализуйте интерфейсShape:IRegularPointynamespace CustomInterfaces{class Square: Shape,IRegularPointy{public Square() { }public Square(string name) : base(name) { }// Метод Draw() поступает из базового класса Shapepublic override void Draw(){Console.WriteLine("Drawing a square");}// Это свойство поступает из интерфейса IPointypublic byte Points => 4;// Это свойство поступает из интерфейса IRegularPointy.public int SideLength { get; set; }public int NumberOfSides { get; set; }// Обратите внимание, что свойство Perimeter не реализовано.}}Здесь мы невольно попали в первую "ловушку", связанную с использованием стандартных реализаций интерфейсов. Свойство
, определенное в интерфейсеPerimeter, в классеIRegularPointyне определено, что делает его недоступным экземпляру классаSquare. Чтобы удостовериться в этом, создайте новый экземпляр классаSquareи выведите на консоль соответствующие значения:SquareConsole.WriteLine("\n***** Fun with Interfaces *****\n");...var sq = new Square("Boxy"){NumberOfSides = 4, SideLength = 4};sq.Draw();// Следующий код не скомпилируется:// Console.WriteLine($"{sq.PetName} has {sq.NumberOfSides} of length{sq.SideLength} and aperimeter of {sq.Perimeter}");Взамен экземпляр
потребуется явно привести к интерфейсуSquare(т.к. реализация находится именно там) и тогда можно будет получать доступ к свойствуIRegularPointy. Модифицируйте код следующим образом:PerimeterConsole.WriteLine($"{sq.PetName} has {sq.NumberOfSides} of length {sq.SideLength} and aperimeter of {((IRegularPointy)sq).Perimeter}");Один из способов обхода этой проблемы — всегда указывать интерфейс типа. Измените определение экземпляра
, указав вместо типаSquareтипSquare:IRegularPointyIRegularPointy sq = new Square("Boxy") {NumberOfSides = 4, SideLength = 4};Проблема с таким подходом (в данном случае) связана с тем, что метод
и свойствоDraw()в интерфейсе не определены, а потому на этапе компиляции возникнут ошибки.PetNameХотя пример тривиален, он демонстрирует одну из проблем, касающихся стандартных реализаций. Прежде чем задействовать это средство в своем коде, обязательно оцените последствия того, что вызывающему коду должно быть известно, где находятся реализации.
Статические конструкторы и члены (нововведение в версии 8.0)
Еще одним дополнением интерфейсов в C# 8.0 является возможность наличия в них статических конструкторов и членов, которые функционируют аналогично статическим членам в определениях классов, но определены в интерфейсах. Добавьте к интерфейсу
статическое свойство и статический конструктор:IRegularPointy