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