Язык программирования C#9 и платформа .NET5
}Использование неявной типизации лишь потому, что она возможна, некоторые считают плохим стилем (если известно, что необходима переменная типа
, то так и следует ее объявлять). Однако, как было показано в главе 13, неявная типизация удобна в сочетании с LINQ, поскольку многие запросы LINQ возвращают перечисления анонимных классов (через проецирование), которые напрямую объявлять в коде C# невозможно. Тем не менее, даже в таких случаях неявно типизированная переменная фактически будет строго типизированной.List<int>В качестве связанного замечания: в главе 6 упоминалось, что
является изначальным родительским классом внутри инфраструктуры .NET Core и может представлять все, что угодно. Опять-таки, объявление переменной типаSystem.Objectв результате дает строго типизированный фрагмент данных, но то, на что указывает эта переменная в памяти, может отличаться в зависимости от присваиваемой ссылки. Чтобы получить доступ к членам объекта, на который указывает ссылка в памяти, понадобится выполнить явное приведение.objectПредположим, что есть простой класс по имени
, в котором определены два автоматических свойства (PersonиFirstName), инкапсулирующие данныеLastName. Взгляните на следующий код:stringstatic void UseObjectVariable(){<b> // Пусть имеется класс по имени Person.</b>object o = new Person() { FirstName = "Mike", LastName = "Larson" };<b> // Для получения доступа к свойствам Person</b><b>.</b><b> // переменную о потребуется привести к Person</b>Console.WriteLine("Person's first name is {0}", ((Person)o).FirstName);}А теперь возвратимся к ключевому слову
. С высокоуровневой точки значения ключевое словоdynamicможно трактовать как специализированную форму типаdynamic— в том смысле, что переменной динамического типа данных может быть присвоено любое значение. На первый взгляд это может привести к серьезной путанице, поскольку теперь получается, что доступны три способа определения данных, внутренний тип которых явно не указан в кодовой базе. Например, следующий метод:System.Objectstatic void PrintThreeStrings(){var s1 = "Greetings";object s2 = "From";dynamic s3 = "Minneapolis";Console.WriteLine("s1 is of type: {0}", s1.GetType());Console.WriteLine("s2 is of type: {0}", s2.GetType());Console.WriteLine("s3 is of type: {0}", s3.GetType());}в случае вызова приведет к такому выводу:
s1 is of type: System.Strings2 is of type: System.Strings3 is of type: System.StringДинамическая переменная и переменная, объявленная неявно или через ссылку на
, существенно отличаются тем, что динамическая переменная не является строго типизированной. Выражаясь по-другому, динамические данные не типизированы статически. Для компилятора C# ситуация выглядит так, что элементу данных, объявленному с ключевым словомSystem.Object, можно присваивать вообще любое начальное значение, и на протяжении периода его существования взамен начального значения может быть присвоено любое новое (возможно, не связанное) значение. Рассмотрим показанный ниже метод и результирующий вывод:dynamicstatic void ChangeDynamicDataType(){
// Объявить одиночный динамический элемент данных по имени t.dynamic t = "Hello!";Console.WriteLine("t is of type: {0}", t.GetType());t = false;Console.WriteLine("t is of type: {0}", t.GetType());t = new List<int>();Console.WriteLine("t is of type: {0}", t.GetType());}Вот вывод:
t is of type: System.Stringt is of type: System.Booleant is of type: System.Collections.Generic.List`1[System.Int32]Имейте в виду, что приведенный выше код успешно скомпилировался и дал бы идентичный результат, если бы переменная
была объявлена с типомt. Однако, как вскоре будет показано, ключевое словоSystem.Objectпредлагает много дополнительных возможностей.dynamicВызов членов на динамически объявленных данных
Учитывая то, что динамическая переменная способна принимать идентичность любого типа на лету (подобно переменной типа
), у вас может возникнуть вопрос о способе обращения к членам такой переменной (свойствам, методам, индексаторам, событиям и т.п.). С точки зрения синтаксиса отличий нет. Нужно просто применить операцию точки к динамической переменной, указать открытый член и предоставить любые аргументы (если они требуются).System.ObjectНо (и это очень важное "но") допустимость указываемых членов компилятор проверять не будет! Вспомните, что в отличие от переменной, определенной с типом
, динамические данные не являются статически типизированными. Вплоть до времени выполнения не будет известно, поддерживают ли вызываемые динамические данные указанный член, переданы ли корректные параметры, правильно ли записано имя члена, и т.д. Таким образом, хотя это может показаться странным, следующий метод благополучно скомпилируется:System.Object