Var c что это
Перейти к содержимому

Var c что это

Ключевое слово var

XYZ School

Одно важное предупреждение: почти невозможно говорить о ключевом слове var и выведении неявных типов без демонстрации инициализации объектов или анонимных типов. Точно так же практически невозможно обсуждать инициализацию объектов или анонимные типы, не упоминая ключевого слова var. Все эти три расширения языка C# тесно связаны между собой.

Прежде чем описать в деталях каждое из этих средств языка — поскольку каждое из них описывает себя в терминах других — давайте взглянем на них всех вместе. Рассмотрим следующий оператор:

В этом примере объявляется переменная по имени mySpouse с использованием ключевого слова var. Ей присваивается значение анонимного типа, инициализированного с помощью новых средств инициализации объектов. Эта единственная строка кода пользуется преимуществами ключевого слова var, анонимных типов и инициализации объектов.

Короче говоря, ключевое слово var позволяет вывести тип данных локальной переменной на основе типа данных, которыми он инициализирован. Анонимные типы позволяют во время компиляции создавать новые типы данных — классы. В соответствии со словом анонимные, эти новые типы данных не имеют имен. Нельзя обычным образом создать анонимный тип данных, поскольку неизвестно, какие переменные-члены он содержит, и невозможно узнать, какие члены он содержит, если неизвестны их типы.

И, наконец, типы этих членов могут быть ясны только после инициализации. Средство инициализации объектов обрабатывает все эти тонкости.

На основе этой строки кода компилятор создаст новый анонимный класс, содержащий два общедоступных члена типа string: первый получит имя FirstName, второй — LastName.

Ключевое слово var неявно типизированной локальной переменной

С появлением в C# анонимных типов возникла новая проблема. Если создается переменная анонимного типа, то переменной какого типа ее можно присваивать? Рассмотрим в качестве примера следующий код:

Какой тип переменной должен быть объявлен для unnamedTypeVar? Это проблемa. В Microsoft решили ее, создав ключевое слово var. Это новое ключевое слово информирует компилятор о том, что он должен неявно вывести тип переменной из инициализатора переменной. Это значит, что переменная, объявленная с ключевым словом var должна иметь инициализатор!

Пропуск инициализатора приводит к возникновению ошибки компиляции, например:

Здесь компилятор сообщит об ошибке:

Поскольку эти переменные подвергаются статической проверке типов во время компиляции, инициализатор необходим, чтобы компилятор мог неявно вывести тип из него. Попытка присвоить значение другого типа где нибудь в коде вызовет ошибку компиляции:

Этот код компилироваться не будет, потому что тип переменной name неявно выводится как string; однако производится попытка присвоить ей целочисленное значение. Как видите, компилятор обязывает переменную сохранять первоначальный тип.

Если вернуться к исходному примеру кода с назначением анонимного типа с использованием ключевого слова var, то код с дополнительной строкой для вывода значения переменной будет выглядеть так, как показано ниже:

Как видите, применение ключевого слова var обеспечивает статический контроль типа, а также гибкость поддержки анонимных типов. Это станет очень важно, когда речь пойдет об операциях проекции типов.

В примерах, приведенных до сих пор, использование ключевого слова var было обязательным, поскольку альтернативы не существовало. Если переменной необходимо присвоить объект анонимного типа, то такая переменная должна обязательно быть объявлена с ключевым словом var.

Однако допускается указывать var при каждом объявлении переменной, если только она правильно инициализируется. Из соображений сопровождаемости рекомендуется этим приемом не злоупотреблять. Понятно, что разработчики всегда должны знать тип данных, с которым они работают, но если вы помните действительный тип данных сейчас, то будет ли это так, когда вы вернетесь к этому коду полгода спустя? Как насчет других разработчиков, которые впоследствии могут заняться сопровождением?

В целях сопровождаемости кода избегайте использования ключевого слова var лишь потому, что это удобно. Применяйте его только там, где это необходимо, например, в случае присваивания переменной объекта анонимного типа.

Выражения инициализации объектов и коллекций

Из-за потребности в динамических типах данных, которые позволяют создавать анонимные типы, возникает необходимость изменения способа инициализации объектов и коллекций. Поскольку выражения теперь представлены в виде лямбда-выражений или деревьев выражений, инициализация объектов и коллекций упростилась.

Инициализация объектов

Инициализация объектов позволяет указывать значения инициализации для общедоступных полей и свойств класса во время создания экземпляра. Для примера рассмотрим следующий код:

До появления средства инициализации объектов в C#, при отсутствии специализированного конструктора, объект типа Address нужно было инициализировать так, как показано ниже:

Такой подход был бы очень неудобным в лямбда-выражениях. Предположим, что нужно запросить значения из источника данных и с помощью операции Select спроецировать определенные члены на объект Address:

Просто отсутствовал бы удобный способ инициализировать члены вновь сконструированного объекта Address. Но не беспокойтесь! На помощь пришла инициализация объектов. Вы можете возразить, что проблема решается простым созданием конструктора, который принимал бы все эти инициализирующие значения при конструировании экземпляра объекта. Да, это так — иногда. Но это сопряжено со сложностями. И как быть в случае анонимного типа? Не проще ли создавать экземпляры объектов, как показано ниже:

Это может решить проблему в лямбда-выражении. Кроме того, помните, что возможности инициализации объектов могут применяться где угодно, а не только в запросах LINQ.

При использовании инициализации объекта компилятор создает экземпляр объекта с помощью конструктора класса без параметров, после чего инициализирует именованные члены указанными значениями. Любые члены, которые не указаны, получают значения по умолчанию, принятые для своих типов данных.

Инициализация коллекций

Поскольку одной только инициализации объектов не достаточно, кто-то в Microsoft должен был сказать: «А как насчет коллекций?». Инициализация коллекций позволяет указывать инициализирующие значения для коллекции — как это делается для объектов. Пример инициализации коллекции приведен ниже:

В дополнение к использованию инициализации коллекций с LINQ, инициализированные коллекции часто удобно создавать в коде, где не присутствуют запросы LINQ.

Анонимные типы

Создание API-интерфейса на уровне языка для обобщенных запросов данных было затруднено в C# из-за нехватки возможностей создания новых типов данных во время компиляции. Если необходимо, чтобы запросы данных извлекали первоклассные элементы на уровне языка, для этого язык должен обладать возможностью создания первоклассных элементов данных уровня языка, которыми в C# являются классы. Поэтому спецификация языка C# теперь включает возможность динамического создания новых безымянных классов и объектов этих классов. Классы такого рода известны как .

Анонимный тип не имеет имени и генерируется компилятором на основе инициализации создаваемого экземпляра объекта. Поскольку класс не имеет имени типа, любые переменные, присваиваемые объекту анонимного типа, должны иметь какой-то способ объявления. Именно в этом состоит предназначение ключевого слова var в C#.

Анонимный тип незаменим при проектировании (projecting) новых типов данных с использованием операций Select или SelectMany. Без анонимных типов при вызове этих операций должны были всегда существовать предопределенные именованные классы. Было бы очень неудобно создавать именованные классы для каждого запроса. Выше обсуждался следующий код создания экземпляра и инициализации объекта:

Если бы вместо использования именованного класса Address возникло желание применить анонимный тип, нужно было бы просто опустить имя класса. Однако тогда не получится сохранить вновь созданный объект в переменной типа Address, потому что он уже не будет переменной типа Address. В таком случае он относился бы к сгенерированному типу, который известен только компилятору. Поэтому пришлось бы изменить также и тип переменной address. Здесь снова на помощь приходит ключевое слово var:

var (справочник по C#)

Начиная с Visual C# 3 переменные, объявленные в области действия метода, получают неявный «тип» var . Неявно типизированные локальные переменные является строго типизированными, как если бы вы объявили тип самостоятельно, однако его определяет компилятор. Следующие два объявления i функционально эквивалентны:

При использовании var с включенными var , всегда подразумевается ссылочный тип, допускающий значение NULL, даже если тип выражения не допускает значения NULL. Анализ состояния NULL в компиляторе обеспечивает защиту от разыменования возможного значения null . Если переменная никогда не назначается выражению, которое может иметь значение NULL, компилятор не выдаст никаких предупреждений. Если переменная присваивается выражению, которое может иметь значение NULL, необходимо проверить, что оно не равно NULL, перед разыменованием, чтобы избежать предупреждений.

Ключевое слово var обычно используется с выражениями вызова конструктора. Использование var позволяет вам не повторять имя типа при объявлении переменной и создании экземпляра объекта, как показано в следующем примере:

Начиная с C# 9.0 вы можете использовать выражение с целевым типом в качестве альтернативы:

При сопоставлении шаблонов в var используется ключевое слово var .

Пример

В следующем примере показаны два выражения запросов. В первом выражении использование var разрешено, но не является обязательным, поскольку тип результата запроса может быть задан явно как IEnumerable<string> . Однако во втором выражении благодаря var результат может быть коллекцией анонимных типов, и имя этого типа доступно только для компилятора. Использование var делает создание нового класса для результата необязательным. Обратите внимание на то, что во втором примере переменная итерации foreach item также типизирована неявно.

О юзабельности var при разработке

Изучая Entity Framework натолкнулся на интересную вещь :

Для создания запроса мы можем использовать var :

var phones = db.Phones.Where(p=> p.Company.Name==»Samsung»);

либо явно указывая тип запроса ,например :

Phone myphone = db.Phones.Where(p=> p.Company.Name==»Samsung»);

что меня натолкнуло на интересный вопрос :

А можно ли при разработке использовать при создании переменных в большинстве случаев var вместо явного указания типа?Если нет, то почему нежелательно?

А теперь наведу несколько примеров ,в которых указаны различия между использованием var явным указанием типов,почему мне кажется что все-таки var в большинстве случаев будет юзабельней и читабельней для разработчиков :

1) Для объявления и дальнейшего использования таких структур как списки и словари(к примеру) которые имеют в себе уже вложенные типы:

Dictionary<Dictionary<String, String>, String> items = new Dictionary<Dictionary<String, String>, String>();

Соответственно через var :

var items = new Dictionary<Dictionary<String, String>, String>();

2) Использование var как итератор при перечислениях в коллекциях :

Код выше — скомпилируется без ошибок ,но при исполнении программы мы получим ошибку приведения типов . Потому что : сам цикл foreach может работать с обоими интерфейсами IEnumerable и IEnumrable<T> . Здесь же результат исполнения имеет тип object и C# компилятор кастит(приводит) это к типу Item . Следовательно , это небезопасно и может привести к ошибке работы программы ,потому что интерфейс IEnumerable может содержать объекты абсолютно любого типа.

Теперь вариант с var :

Здесь же тип x будет object если интерфейс IEnumerable и T если используется IEnumerable<T>

3) И само собой — использование var при запросах + либо получение объекта с уже определенным типом :

Или запрос через подход LINQ To Objects :

UPD: ну и пример с использованием анонимных типов :

Краткий вывод из примеров выше : var — достаточно неплохая вещь ,поскольку он строго типизирован + правильное название переменных позволяет ещё и повысить читабельность . Что в суме значительно повышает эффективность кода без ущерба для безопасности

Вопрос в том : есть ли преимущества использования явного указания типов при объявлении переменных перед var ?

Я просто новатор в этом деле и хотелось бы услышать мнение опытных людей.Спасибо за конструктивный ответ!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *