C# представляет собой развивающийся язык. В этой статье рассматриваются новые функции, добавленные в C # 4.0 (а также короткое описание нововведений в предыдущих версиях), что в совокупности улучшает читаемость кода и предоставляет вам возможность использовать LINQ для запросов к динамическим источникам данных. Примеры, приведенные в этом обзоре показывают пути улучшения модели кодирования для чтения данных из различных источников, включая текстовые файлы, и каким образом объединять данные из COM-Interop источника для LINQ запросов к объектам.
C# 2.0
Generics/Обобщения – новая возможность языка, позволяющая создавать обобщенные алгоритмы, Итераторы (yield keyword) – механизм, упрощающий создание перечислителей (реализации интерфейса IEnumerable), Анонимные методы/anonymous methods (delegate keyword) – возможность инициализировать делегаты телами методов, Partial types (классы) – возможность разбивать код одного класса по нескольким файлам, упрощенный синтаксис инициализации делегатов.
C# 3.0
Ключевые слова select, from, where, позволяющие делать запросы из SQL, XML, коллекций и т. п. (запрос, интегрированный в язык, Language Integrated Query, или LINQ), Инициализация объекта вместе с его свойствами, лямбда-выражения ( lambda expressions (=>)), деревья выражений (лямбда-выражения могут представляться в виде структуры данных), безымянные типы (var-ы), методы-расширения — добавление метода в существующий класс с помощью ключевого слова this при первом параметре статической функции, автоматические свойства.
Важно! C# 3.0 совместим с C# 2.0 по генерируемому MSIL-коду, улучшения в языке — чисто синтаксические и реализуются на этапе компиляции. |
Улучшения в C# 4.0
Microsoft разделила новые функции на следующие четыре категории:
• Именованые и необязательные параметры
• Динамическое связывание
• Ковариантность и контрвариантность
• Улучшенное взаимодействие с COM
Соглашения
Для рассмотрения примеров, будем считать, что опрелены следующие классы:
public class Person { public string FirstName { get; set; } public string LastName { get; set; } } public class Customer : Person { public int CustomerId { get; set; } public void Process() { ... } } public class SalesRep : Person { public int SalesRepId { get; set; } public void SellStuff() { ... } }
Именованые и необязательные параметры
Поддержка необязательных параметров позволяет передать методу значение по умолчанию, следовательно вы не должны указывать его при каждом вызове метода. Это очень удобно, когда у вас есть несколько перегруженных версий метода. "Древний" подход выглядел так:
public void Process( string data ) { Process( data, false ); } public void Process( string data, bool ignoreWS ) { Process( data, ignoreWS, null ); } public void Process( string data, bool ignoreWS, ArrayList moreData ) { //Наш код }
Причиной перегрузки метода Process является намерение избежать необходимости постоянно включать "false, null" в третьем вызове метода. Теперь предположим, что в 99% случаев динамический массив 'moreData' не будет предоставляется - с этой т.з. выглядит "неправильным" передавать null так много раз:
Следующие 3 вызова эквивалентны
Process( "foo", false, null ); Process( "foo", false ); Process( "foo");
Новый подход выглядит так:
public void Process( string data, bool ignoreWS = false, ArrayList moreData = null ) { // Наш код }
// Примечание: строковая переменная data должна передаваться всегда, т.е. у нее нет значения по умолчанию
Теперь у нас есть всего лишь один метод Process вместо трех, но те три способа вызова, которые мы рассматривали выше все еще работают (и эквивалентны между собой):
ArrayList myArrayList = new ArrayList(); Process( "foo" ); //Правильный вызов Process( "foo", true ); //Правильный вызов Process( "foo", false, myArrayList ); //Правильный вызов Process( "foo", myArrayList );
// Неправильно! См. ниже описание именованых парамертов...
Именованые параметры
В предыдущем примере (выше) мы увидели, что следующий вызов неправилен:
Process( "foo", myArrayList );
Давайте разберемся: если булева переменная ignoreWS не обязательна (т.е. носит опциональный характер), почему мы не можем просто проигнорировать/опустить ее? Важными причинами могут являтся читабельность и сопровождаемость написанного кода, но, что еще более важно - при таком "подходе" невозможно узнать какой из параметров вы пытаетесь передать, т.е. если у вас к примеру два параметра одного и того же типа, то компилятор не может узнать какой из них вы имеете ввиду. Представьте себе метод с 10-ю необязательными параметрми и вы передаете ему только один ArrayList. Так как ArrayList наследуется от object, IList и IEnumerable, то становится невозможным определить, каким образом его использовать. Теперь думаю понятно в чем трудность. В свою очередь, "именованые параметры" предоставляют элегантное решение:
ArrayList myArrayList = new ArrayList(); Process( "foo", true ); // это правильный синтаксис, и moreData проигнорирован Process( "foo", true, myArrayList ); //это также правильный синтаксис Process( "foo", moreData: myArrayList); //это правильный синтаксис и ignoreWS проигнорирован Process( "foo", moreData: myArrayList, ignoreWS: false ); //Правильно, но не приемлимо...
Имейте ввиду то, что если параметр имеет значение по умолчанию, его можно опустить.
Динамическое связывание (Dynamic binding)
Пожалуй наибольшей инновацией в C# 4.0 является динамическое связывание (Dynamic binding). Реализация данной функции в C# была стимулирована примерами таких динамических языков как Python, Ruby, JavaScript и SmallTalk. Динамическое свзяывание "откладывает" связывание (процесс определения типов и членов) с этапа компиляции до времени выполнения. Хотя C# остается преимущественно статически типизированным языком - переменные типа "dynamic" определяются методом "позднего связывания". Ну ОК, давайте перейдем от слов к делу :) Уверен Вы имели дело с кодом, наподобие этого:
public object GetCustomer() { Customer cust = new Customer(); ... return cust; } ... Customer cust = GetCustomer() as Customer; if( cust != null ) { cust.FirstName = "foo"; }
Примите во внимание, что метод GetCustomer возвращает object.
Материалы взяты с сайта www.codeproject.com
Comments