WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!


Pages:     || 2 |

Курс "Обзор перспективных технологий Microsoft.NET"

Лекция 7. C# 3.0

(2 лекции)

От C# 1.0 к C# 2.0

В конце 2005го года вышла вторая версия.NET Framework. В ней появились существенные улучшения, которые, в частности, отразились и на языке C#, входящем в стандартную поставку. В C# версии 2.0 появились:

Обобщения (generics) Частичные классы (partial classes) Анонимные делегаты Улучшения для создания перечислителей И т.д.

(надо понимать, что эти возможности появились благодаря соответствующим изменениям в CLR, а не в отдельно взятом языке C#).

Основное улучшение – появление обобщений, некоторого аналога шаблонов С++, которых так не хватало в первой версии. Обобщения позволяют перенести многие проверки со времени исполнения на время компиляции, избежать ненужных операций упаковки и распаковки, уменьшить количества кода.

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

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

Замечание. В отличие от первой версии C#, вторая версия на момент создания этого курса лекций не является стандартом. Стандартизация была весьма весомым аргументом в пользу языка C#, и позволила сторонним фирмам предлагать свои реализации, что невозможно в данный момент со второй версией.

Предпосылки к дальнейшим изменениям Каковы были предпосылки в создании новой версии С#? Создатель языка Андерс Хейлсберг (Anders Hejlsberg) утверждает, что за последние годы программисты получили все, что им нужно для объектноориентированного проектирования и программирования. На этом движение вперед закончилось и ситуация стабилизировалась. Однако существуют области, по своей природе не являются объектноориентированными и с которыми не всегда удобно работать в ООстиле. Одним из таких примеров является работа с реляционными базами данных. Для работы с БД давнымдавно существует стандарт доступа – SQL, structured query language. Именно SQL используется в ADO.NET, то, что называется under the hood, в скрытом коде DataAdapter’ов, а иногда и явно задается программистом как параметр объекта Command.

С помощью SQL программист получает всю мощь доступа к реляционной БД, однако на его плечи перекладывается множество сопутствующих проблем: отсутствие статических проверок типов, самостоятельная обработка результатов запросов и т.п. Вот, что говорит Андерс:

«If we just take languages like C# and SQL, whenever I talk to the C# programming crowd, I ask them, "How many of you access a database in your applications"? They laugh and look at me funny, and then they all raise their hands.

So from that I take away that when you're learning to program in C#, you're actually not just learning to program in C#. You're also learning SQL. And you're also learning all the APIs (application programming interfaces) that go along with bridging that gap. And you're learning a whole style of writing a distributed application. But interestingly, we've come to accept that that's just how it is. But it doesn't necessarily have to be that way. The two worlds are actually surprisingly unintegrated».

Одним из лозунгов создателей языка C# 3.0 стал "создать встроенный в язык механизм запросов". Этот лозунг вылился в появление проекта LINQ, language integrated query. LINQ – одно из главных новшеств в 3й версии языка.

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

Краткий список изменений C# 3. Вот краткий список нововведений в третьей версии языка:

Автоматический вывод типов для локальных переменных Инициализаторы объектов и коллекций Анонимные типы Методы «расширения» (extension methods) Лямбдавыражения Запросы (query expressions) Деревья выражений (expression trees) Автоматический вывод типов Первым улучшением, которое мы рассмотрим, стал автоматический вывод типов. В самом деле, в некотором виде автоматический вывод типов появился еще во второй версии C#. Помните, там впервые появились анонимные делегаты, использование которых было бы невозможно без вывода их типов. Вероятно, создатели решили облегчить жизнь программистам и в остальных местах, где возможно автоматически вывести типы, в частности, при описании переменных с инициализаторами. Для описания переменных, которые должны получить тип автоматически, введено ключевое слово var:



var myInt = 1; // тип – целое число var myString = "Goodbye, World"; // тип – строка var evenNumbers = new int[] {2, 4, 6, 8}; // тип – int[] foreach(var evenNumber in evenNumbers) // тип int По понятным причинам запрещены определения, не допускающие вывода типов:

var dontKnowType; // нет инициализации, неоткуда выводить тип var someNull = null; // кто ж знает, что это за null var someCollection = { 1, 2, 3 }; // кто ж знает, что это за коллекция Инициализаторы объектов и коллекций Логичным  улучшением стало более легкое создание сложных структур и классов. Вместо Student myStudent = new Student();

myStudent.LastName = "Ivanov";

myStudent.AverageMark = 3.5;

можно написать Student myStudent = new myStudent { LastName = "Ivanov", AverageMark = 3.5 };

Или даже так, вместо List University = new List();

Student Ivanov = new Student();

Ivanov.LastName = "Ivanov";

myStudent.AverageMark = 3.5;

Student Petrov = new Student();

Petrov.LastName = "Petrov";

myStudent.AverageMark = 4.5;

University.Add(Ivanov);

University.Add(Petrov);

можно написать коротко:

List University = new List { Ivanov = new Student { LastName = "Ivanov", AverageMark = 3.5 }, Petrov = new Student { LastName = "Petrov", AverageMark = 4.5 } };

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

var Ivanov = new { LastName = "Ivanov", AverageMark = 3.5 };

var Petrov = new { LastName = "Petrov", AverageMark = 4.5 };

Этот код создаст анонимный класс (один, а не два) с двумя свойствами – LastName и AverageMark, причем переменные Ivanov и Petrov можно будет присваивать друг другу. Гарантируется, что в конкретной сборке будет только один тип с таким набором полей (т.е. типы не будут «плодиться», вне зависимости от того, объявлялись ли такие же переменные в других функциях или классах).

Методы расширения Методы расширения – крайне полезный механизм для надстройки существующего контракта некоторого класса. Как нам иногда хотелось добавить к классу из чужой библиотеки (скажем, библиотеки Microsoft) какойнибудь нужный нам метод, который создатели класса по непонятным для нас причинам забыли! Увы, нам оставалось только порождать подклассы, да и то, только в тех случаях, когда нужный нам класс не являлся «запечатанным» (sealed).

В 3й версии C# появилась такая возможность – с помощью методов расширения. Метод расширения – это некоторый статический метод некоторого статического класса, который чудесным образом добавляет метод с таким же именем к существующему классу. Такой метод должен иметь в первом параметре слово this:

public static class StudentExtension { public static float GetAverageMark(this Student student) { return student.AverageMark;

} } Имея такое описание, мы вправе писать следующим образом:

var Ivanov = new Student { "Ivanov", 3.5 };

Console.WriteLine(Ivanov.GetAverageMark());

несмотря на то, что исходный класс не определял метода GetAverageMark.

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

Методы расширения, как мы увидим в дальнейшем, очень важны для создания языка запросов.

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





Лямбдаисчисление придумал еще Чёрч в начале 20го века, как основу для формального изучения свойств функций. Впоследствии оно привело к появлению функциональных языков программирования.

Функциональное программирование использует математическое понятие функции для выражения концепции действия. Подобно обычным математическим функциям, функции функциональных языков отображают одни объекты (аргументы) в другие (значения). Причём, в отличие от функций обычных императивных языков, значения функций однозначно определяются их аргументами и не зависят от истории вычислительного процесса (то бишь, от контекста, такого, как глобальные переменные, статические переменные функции или доступных классов и т.п.). Существует даже мнение, что обучение студентов на ITнаправлениях стоит начинать с функциональных языков, т.к. их свойства описываются математически точно, а исполнение однозначно предсказуемо.

В функциональном программировании нет разницы между «данными» и «операциями», т.к. функции в функциональных языках являются объектами «первого класса». Понятие «первоклассных» элементов языка программирования было введено Кристофером Стрейчи. Он отметил, что языки программирования налагают различные ограничения на методы использования элементов языка. Элементы первого класса – это элементы с наименьшим количеством ограничений. Важные свойства таких первоклассных элементов:

На них можно ссылаться посредством переменных Их можно включать в структуры данных Их можно передавать как параметры Они могут быть возвращены в качестве результата В отличие от большинства императивных языков (за исключением разве что Алгола68), функциональные языки предоставляет функциям статус первого класса. Это создаёт трудности для их эффективной реализации, но приводит к значительному увеличению выразительной силы этих языков.

Функциональные языки (не все, правда, но в основном) опираются на лямбдавыражения. Лямбдавыражение – это анонимная функция от одного аргумента. Для таких выражений существует только одна операция – функциональная композиция. Однако этого достаточно, чтобы определить функции со многими аргументами, логические предикаты, операторы наподобие ifthenelse и даже рекурсию. Лямбдавыражение записывается так:

л x. x + 2 – функция, которая по своему аргументу возвращает его сумму с 2 (имя аргумента не имеет значения, можно написать также л у. у + 2, функция при этом останется одна и та же).

л x. л y. x – y – композиция двух функций, которая представляет собой третью функцию – x – y (такие функции принято сокращать до л x y. x – y, т.н. «карринг»).

Более подробно о лямбдаисчислении можно прочитать здесь – http://en.wikipedia.org/wiki/Lambda_calculus.

Так вот, лямбдавыражения теперь есть и в C#, причем в довольно похожем стиле. Для лямбдавыражений введен новый токен ‘=>’:

var WriteAverageDelegate = Student => Console.WriteLine(Student.AverageMark);

WriteAverageDelegate(Ivanov);

Это эквивалентно следующему коду на версии 2.0:

// на уровне класса delegate void WriteAverageDelegate(Student student);

// в теле метода класса WriteAverageDelegate myDelegate = delegate(Student student) { Console.WriteLine(student.AvMark); };

myDelegate(Ivanov);

Можно определять лямбдавыражения без параметров (слева от знака => указать пустые скобки – (), можно со многими параметрами, перечислив их через запятую в скобках слева от знака =>). Более подробно о лямбдавыражениях – на следующей лекции.

Язык запросов (Query expressions) Язык запросов – это собственно то, ради чего затевался проект LINQ. А LINQ – это набор расширений языка (вернее, языков – C# и VB.NET) и модель программирования, которая позволяет создавать унифицированные запросы к объектам, базам данных и XML. Новый язык запросов (если переводить дословно, «выражения запроса») весьма похож на SQL:

from student in Students where student.AverageMark > 4. select student.LastName;

Pages:     || 2 |










© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.