Оператор is в C# аллоцирует память в куче (heap), если используется значимый тип Оператор is в C# используется для проверки, соответствует ли экземпляр определенному типу или интерфейсу. Оператор is проверяет совместимость типов во время выполнения и возвращает true, если экземпляр является указанным типом, или false, если это не так. Если указанный тип соответствует одному из родителей экземпляра, то оператор is вернет true. Например, здесь if будет true. ```csharp class Parent { } class Child : Parent { } var child = new Child(); if (child is Parent) ``` <br> Оператор `is` в C# возвращает `false` если проверяемая переменная имеет значение `null`. Он проверяет, является ли объект определённого типа, и не считает `null` допустимым экземпляром какого-либо типа. Пример: ```csharp object myObj = null; bool isString = myObj is string; // будет false // Комментарий: isString будет равен false, потому что myObj равен null ``` <br> <br> Начиная с версии C# 9.0 можно использовать **not** (отрицание) ```csharp if (result is not null) { Console.WriteLine(result.ToString()); } ``` ### Использование оператора is для проверки на соответствие типа экземпляра с указанным типом. ##### Пример с классами ```csharp class Animal { } class Mammal : Animal { } class Reptile : Animal { } static void Main(string[] args) { Animal animal = new Mammal(); if (animal is Mammal) { Console.WriteLine("Это млекопитающее."); } else if (animal is Reptile) { Console.WriteLine("Это рептилия."); } else { Console.WriteLine("Тип животного неизвестен."); } } ``` В переменной animal хранится экземпляр класса Mammal. Хотя тип переменной animal объявлен как Animal, фактический экземпляр, на который она ссылает, является экземпляром класса Mammal. Оператор **is** проверяет, является ли объект animal экземпляром класса Mammal или Reptile. В данном случае, так как animal является экземпляром класса Mammal, условие animal **is** Mammal вернет true и будет выведено "Это млекопитающее." <br> <u>Ремарка насчет Animal animal = new Mammal();:</u> Это возможно, потому что Mammal является производным классом от Animal, и все объекты класса Mammal также являются объектами класса Animal. Это пример полиморфизма в объектно-ориентированном программировании, который позволяет использовать объекты производного класса как объекты базового класса. Однако, обратите внимание, что если вы хотите использовать специфичные для класса Mammal методы или свойства, вам придется выполнить явное приведение типов, используя оператор as или is, или другие способы приведения типов, для того чтобы преобразовать переменную animal обратно в тип Mammal. ##### Пример с интерфейсами ```csharp interface IFlyable { void Fly(); } class Bird : IFlyable { public void Fly() { Console.WriteLine("Птица летит."); } } class Airplane : IFlyable { public void Fly() { Console.WriteLine("Самолет летит."); } } static void Main(string[] args) { IFlyable flyable = new Bird(); if (flyable is Bird) { Console.WriteLine("Это птица."); } else if (flyable is Airplane) { Console.WriteLine("Это самолет."); } else { Console.WriteLine("Тип объекта неизвестен."); } } ``` Класс Bird реализует интерфейс IFlyable. Мы создаем новый экземпляр класса Bird и присваиваем его переменной flyable, которая имеет тип IFlyable. Оператор **is** проверяет, является ли объект flyable экземпляром класса Bird или Airplane. В данном случае, так как flyable является экземпляром класса Bird, условие flyable **is** Bird вернет true и будет выведено "Это птица." <br> <u>Ремарка для IFlyable flyable = new Bird();:</u> Такое присваивание возможно, потому что класс Bird реализует интерфейс IFlyable, и все объекты класса Bird можно использовать как объекты, соответствующие этому интерфейсу. Это пример полиморфизма на основе интерфейсов в объектно-ориентированном программировании, который позволяет работать с объектами разных типов, используя общий интерфейс (в данном случае, переменную типа IFlyable). Однако, обратите внимание, что если вы хотите использовать специфичные для класса Bird методы или свойства, вам придется выполнить явное приведение типов, используя оператор as или is, или другие способы приведения типов, для того чтобы преобразовать перемен ### Использование оператора is для проверки на null. ```csharp object obj = null; if (obj is null) { Console.WriteLine("Объект равен null."); } else { Console.WriteLine("Объект не равен null."); } ``` В этом примере, так как переменная obj равна null, условие obj is null вернет true, и будет выведено сообщение "Объект равен null." Это альтернативный способ проверки на null, и вы можете использовать его вместо оператора \==. <br> ### Использование оператора is для безопасного приведения типов ##### Пример 1 ```csharp class Shape { } class Circle : Shape { } class Square : Shape { } static void Main(string[] args) { Shape shape = new Circle(); if (shape is Circle circle) { Console.WriteLine("Это круг."); // Здесь вы можете использовать переменную 'circle' как экземпляр класса Circle. } else if (shape is Square square) { Console.WriteLine("Это квадрат."); // Здесь вы можете использовать переменную 'square' как экземпляр класса Square. } else { Console.WriteLine("Тип фигуры неизвестен."); } } ``` Если shape является экземпляром класса Circle или Square, соответствующая переменная (например, circle или square) будет инициализирована этим экземпляром, и вы сможете использовать её в блоке кода. Если shape не является экземпляром указанного класса, условие вернет false, и переменная не будет инициализирована. Изменения circle влияют напрямую на shape? То есть если я изменю значение поля у circle, то shape оно тоже изменится? Да, вы абсолютно правы. Если shape является экземпляром класса Circle и вы выполняете паттерн-матчинг с использованием is, то переменная circle будет ссылаться на тот же объект, что и shape. В результате, любые изменения, сделанные в circle, также отразятся на shape, так как обе переменные ссылаются на один и тот же объект в памяти. Пример: ```csharp public class Shape { } public class Circle : Shape { public int Radius { get; set; } } Shape shape = new Circle { Radius = 5 }; if (shape is Circle circle) { circle.Radius = 10; Console.WriteLine(quot;Radius of circle: {circle.Radius}"); // Вывод: Radius of circle: 10 } if (shape is Circle originalCircle) { Console.WriteLine(quot;Radius of shape: {originalCircle.Radius}"); // Вывод: Radius of shape: 10 } ``` В этом примере, после изменения радиуса circle, радиус shape (приведенный обратно к типу Circle) также изменяется, потому что обе переменные ссылаются на один и тот же объект в памяти. ##### Пример 2 ```csharp object shape = GetShape(); switch (shape) { case Circle c: WriteLine(quot;Круг с радиусом {c.Radius}"); break; case Rectangle s when s.Length == s.Width: WriteLine(quot;Квадрат со стороной {s.Length}"); break; case Rectangle r: WriteLine(quot;Прямоугольник со сторонами {r.Length} и {r.Width}"); break; default: WriteLine("<неизвестная форма>"); break; } ``` В этом примере используется оператор switch с шаблонным сопоставлением (pattern matching), где внутри case оператор is используется для проверки типа shape. Это позволяет удобно обрабатывать различные случаи, основанные на типе объекта и его свойствах. ### Использование оператора is для сопоставления с константами ```csharp if (someInt is 42) { // Действия, если someInt равен 42 } ```