[Developer's community]

C# 4.0 Описание новых функций

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 (2) -

  • Quite nice topic!
  • Норм статья, только мало подробностей, тем более насколько я знаю в 4ом шарпе намного больше изменений было

Add comment

Loading