суббота, 4 июня 2011 г.

Когда следует использовать ключевое слово 'var' в C#?


Небольшое введение.
Контекстное ключевое слово 'var' было впервые представленное в C# 3.0. Оно описано, как "контекстное" т.к. является ключевым в определенном контексте. В остальных случаях - это обычный идентификатор.

Контекстные ключевые слова не являются чем-то новым. Еще в C# 1.0 были представлены такие контекстные ключевые слова, как get, set, value, add и remove - которые используются в контексте определения свойств и событий. Другие контекстные ключевые слова были добавлены в последующих версиях.

'var' является инструкцией для компилятора C#, позволяющей определить тип локальной переменной из типа присваиваемого ей значения. Например:
var list = new List(); // list принадлежит типу List
var count = 3; // count принадлежит типу int
var greeting = "Hello"; // greeting принадлежит типу string
var var = 'c'; // var (в роли имени переменной) принадлежит типу 'char'

Несмотря на то, что последний пример является допустимым, он в любом случае из серии bad practice.

Как только тип переменной будет определен, его уже нельзя будет изменить:
greeting = 5; // недопустимо т.к. greeting имеет тип string

'var' является строго типизированным, хотя может показаться, что это не так.

Так в чем же заключается проблема?
'var' является одним из самых спорных дополнений в C#.

Одни C# разработчики любят его и используют где только это возможно; другие же разработчики, напротив, ненавидят 'var' и используют его тогда, когда другого варианта просто нет. Остальные же находятся где-то между этими двумя крайностями, хотя многие и не имеют продуманной или четкой политики по этому поводу.

Те, кто любит 'var', говорят, что его использование уменьшает количество ввода, количество строк и убирает необходимость в дублировании типа переменной с двух сторон оператора присваивания во время инициализации объекта (многие разработчики сетовали по этому поводу на версии 1.0 и 2.0). В любом случае, если закрались, какие-либо сомнения в отношении типа переменной, то Intellisense поможет их развеять.

Те, кто ненавидит 'var', говорят, что код становится нечитабельным (а обычно код читают чаще, нежели пишут) и подстрекают к использованию "уродливой" венгерской нотации чтобы тип переменной был ясен из ее имени. К примеру, iCount - переменная типа int или sGreeting - тип string. Да и во время "чтения" кода Intellisense не всегда может быть под рукой.

Даже выбор ключевого слова для не типизированной переменной сомнителен. Многие разработчики считают, что 'var' является плохим выбором из-за намека на слабо типизированное ключевое слово 'var' в Java Script или на варианты в языках, основанных на COM (таких как VB6), которые могут принимать значения любых типов.

Последняя версия Visual C++ использует ключевое слово 'auto' для выполнения аналогичной роли. Вероятно, подобный выбор для C# был бы лучше, хотя наверняка впоследствии начали бы поступать жалобы от программистов, работающих в автомобильной индустрии!

Когда вы должны использовать 'var'?
'var' необходимо использовать при объявлении переменных анонимного типа или коллекций анонимных типов. По определению эти типы не имеют имен (у них нет имен, по которым к ним можно было бы нормально обращаться из C#). Поэтому нужно писать:
var anonymous = new{FirstName = "John", LastName = "Doe"};
var query = from name in names where name.StartsWith("A") select new { Initial = name[0], LastName = name.Split(' ')[1]};

Когда 'var' использовать нельзя?
Использование 'var' запрещено для объявления локальных переменных внутри методов или свойств, включая итерационные переменные в 'for' и 'foreach' выражениях. Это значит, что 'var' запрещено использовать в любом из следующих сценариев:
- в качестве типа поля
- в качестве типа параметра
- в качестве типа возвращаемого методом или свойством
- в качестве типа параметра в обобщенном типе или методе
Его также запрещено использовать, если уже есть одноименный тип в той же области видимости:
class var
{ 
   static void Main()
  {
     var v = "Hello"; // нельзя неявно привести к типу из 'string' в 'var'  
  }
}

Не может быть использован в выражениях, где тип 'var' нельзя определить:
var n = null; // Нельзя присвоить 'null' неявно типизированной локальной переменной

Когда следует использовать 'var'?
Так существует ли золотая середина, с которой могли бы согласиться те из нас, кто не определился со своим отношением к 'var'?

Главное возражение в отношении беспорядочного использования 'var' состоит в том, что код становится нечитабельным т.к. сложно, взглянув на код, сразу сказать к какому типу принадлежит переменная - придется сначала хорошенько задуматься, но даже после этого не всегда удастся правильно ответить на данный вопрос.

Это говорит о том, что было бы разумно ограничить использование 'var' случаями, когда тип очевиден т.к. он явно используется с правой стороны оператора присваивания. Это следующие случаи:
- оператор 'new'
- 'static' методы, возвращающие значение такого же типа
- выражения с простым приведением типов
- выражения, включающие преобразование с помощью оператора 'as'

Несколько примеров для наглядности:
var ht = new Hashtable(); //оператор 'new'
var dt = DateTime.Parse("1/1/2011"); //статический метод
ht.Add(1,dt);
var dt2 = (DateTime)ht[1]; //простое приведение типов
var dict = ht as IDictionary; //преобразование с помощью оператора 'as'

Конечно, во всех этих случаях вы можете возразить, что не обязательно присвоили бы эти значения переменными “очевидного” типа. А присвоили бы их скорее переменной типа, к которой “очевидный” тип неявно преобразуется (скажем “object” в вышеупомянутых случаях). Однако, в таком случае, ничего не мешало бы явно определить тип переменной т.к. уже имеется смешение явных и неявных присваиваний (в случае если вы следовали этим условиям).

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

Хотя это крайне субъективно, но с моей точки зрения все это не имеет смысла, пока имя необобщенного типа состоит, по меньшей мере, из восьми символов, что удобно исключает из рассмотрения встроенные типы (string, double, decimal и т.д.).

Не все ли равно, что вы делаете?
Я считаю, что не все равно.

Когда вы пишите код, вас не должен мучить вопрос, “а стоит ли здесь использовать 'var' или нет?” Вам нужно четкое понимание того, когда (если вообще необходимо) следует им пользоваться, дабы решение принималось моментально.

Аналогично, когда вы просматриваете код, тратить несколько секунд пытаясь решить, к какому типу принадлежит переменная не очень то и хочется – хочется определить это моментально.

Даже если вы не согласны с моим "здравым предложением о золотой середине", я надеюсь, что, по крайней мере, данная статья поможет вам решить вопрос с выбором стратегии в использовании 'var', подходящей именно вам!

Перевод статьи: When should you use the 'var' keyword in C#?

2 комментария:

  1. класс, лучше чем у Троелсена!!

    ОтветитьУдалить
  2. Narek. мой бред по пьяни даже лучше чем статьи в переводе у Троелсена))
    А эта статья зачетная.

    ОтветитьУдалить