Шрифт:
Интервал:
Закладка:
namespace MyExtensions
{
static class ObjectExtensions
{
// Определить расширяющий метод для System.Object.
public static void DisplayDefiningAssembly(
this object obj)
{
Console.WriteLine("{0} lives here:nt->{1}n", obj.GetType().Name,
Assembly.GetAssembly(obj.GetType()));
}
}
}
Чтобы использовать такое расширение, приложение должно импортировать пространство имен, определяющее расширение (и возможно добавить ссылку на внешнюю сборку). Затем можно приступать к написанию кода:
// Поскольку все типы расширяют System.Object, все
// классы и структуры могут использовать это расширение.
int myInt = 12345678;
myInt.DisplayDefiningAssembly();
System.Data.DataSet d = new System.Data.DataSet();
d.DisplayDefiningAssembly();
При работе c LINQ вам редко (если вообще когда-либо) потребуется вручную строить собственные расширяющие методы. Тем не менее, создавая выражения запросов LINQ, вы на самом деле будете применять многочисленные расширяющие методы, уже определенные разработчиками из Microsoft. Фактически каждая операция запроса LINQ в C# представляет собой сокращенную запись для ручного вызова лежащего в основе расширяющего метода, который обычно определен в служебном классе System.Linq.Enumerable.
Анонимные типы
Последним средством языка С#, описание которого здесь кратко повторяется, являются анонимные типы, рассмотренные в главе 11. Данное средство может использоваться для быстрого моделирования "формы" данных, разрешая компилятору генерировать на этапе компиляции новое определение класса, которое основано на предоставленном наборе пар "имя-значение". Вспомните, что результирующий тип составляется с применением семантики на основе значений, а каждый виртуальный метод System.Object будет соответствующим образом переопределен. Чтобы определить анонимный тип, понадобится объявить неявно типизированную переменную и указать форму данных с использованием синтаксиса инициализации объектов:
// Создать анонимный тип, состоящий из еще одного анонимного типа.
var purchaseItem = new {
TimeBought = DateTime.Now,
ItemBought =
new {Color = "Red", Make = "Saab", CurrentSpeed = 55},
Price = 34.000};
Анонимные типы часто применяются в LINQ, когда необходимо проецировать в новые формы данных на лету. Например, предположим, что есть коллекция объектов Person, и вы хотите использовать LINQ для получения информации о возрасте и номере карточки социального страхования в каждом объекте. Применяя проецироавние LINQ, можно предоставить компилятору возможность генерации нового анонимного типа, который содержит интересующую информацию.
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})Роль LINQ
На этом краткий обзор средств языка С#, которые позволяют LINQ делать свою работу, завершен. Однако важно понимать, зачем вообще нужен язык LINQ. Любой разработчик программного обеспечения согласится с утверждением, что значительное время при программировании тратится на получение и манипулирование данными. Когда говорят о "данных", на ум немедленно приходит информация, хранящаяся внутри реляционных баз данных. Тем не менее, другими популярными местоположениями для данных являются документы XML или простые текстовые файлы.
Данные могут находиться в многочисленных местах помимо указанных двух распространенных хранилищ информации. Например, пусть имеется массив или обобщенный тип List<T>, содержащий 300 целых чисел, и требуется получить подмножество, которое удовлетворяет заданному критерию (например, только четные или нечетные числа, только простые числа, только неповторяющиеся числа больше 50). Или, возможно, при использовании API-интерфейсов рефлексии необходимо получить в массиве элементов Туре только описания метаданных для каждого класса, производного от какого-то родительского класса. На самом деле данные находятся повсюду.
До появления версии .NET 3.5 взаимодействие с отдельной разновидностью данных требовало от программистов применения совершенно несходных API-интерфейсов. В табл. 13.1 описаны некоторые популярные API-интерфейсы, используемые для доступа к разнообразным типам данных (наверняка вы в состоянии привести и другие примеры).
Разумеется, с такими подходами к манипулированию данными не связано ничего плохого. В сущности, вы можете (и будете) работать напрямую с ADO.NET, пространствами имен XML, службами рефлексии и разнообразными типами коллекций. Однако основная проблема заключается в том, что каждый из API-интерфейсов подобного рода является "самостоятельным островком", трудно интегрируемым с другими. Правда, можно (например) сохранить объект DataSet из ADO.NET в документ XML и затем манипулировать им посредством пространств имен System.xml, но все равно манипуляции данными остаются довольно асимметричными.
В рамках API-интерфейса LINQ была предпринята попытка предложить программистам согласованный, симметричный способ получения и манипулирования "данными" в широком смысле этого понятия. Применяя LINQ, прямо внутри языка программирования C# можно создавать конструкции, которые называются выражениями запросов. Такие выражения запросов основаны на многочисленных операциях запросов, которые намеренно сделаны похожими внешне и по поведению (но не идентичными) на выражения SQL.
Тем не менее, трюк заключается в том, что выражение запроса может использоваться для взаимодействия с разнообразными типами данных — даже с теми, которые не имеют ничего общего с реляционными базами данных. Строго говоря, LINQ представляет собой термин, в целом описывающий сам подход доступа к данным. Однако в зависимости от того, где применяются запросы LINQ, вы встретите разные обозначения вроде перечисленных ниже.
• LINQ to Objects. Этот термин относится к действию по применению запросов LINQ к массивам и коллекциям.
• LINQ to XML. Этот термин относится к действию по использованию LINQ для манипулирования и запрашивания документов XML.
• LINQ to Entities. Этот аспект LINQ позволяет использовать запросы LINQ внутри API-интерфейса ADO.NET Entity Framework (EF) Core.
- Понимание SQL - Мартин Грубер - Базы данных