Теперь вы можете создать объект, который не имеет представления в виде класса на этапе проектирования. При этом компилятор создает для вас класс без названия (анонимный). Эта функциональная возможность называется анонимными типами (anonymous types). Анонимные типы обеспечивают важнейшую поддержку запросов LINQ. С их помощью столбцы данных, возвращенные по запросу, могут быть представлены как объекты (подробнее об этом далее). Анонимные типы компилируются в объекты классов со свойствами "только для чтения".
Рассмотрим пример того, как следует создавать анонимный тип. Предположим, что вы хотите создать объект, который имеет свойства Name и PhoneNumber. Однако у вас нет такого определения класса в вашем коде. Для этого вы можете объявить анонимный тип.
□ VB:
Dim emp = New With {.Name = "Joe Smith", _
.PhoneNumber = "123-123-1234"}
□ C#:
var emp = new { Name = "Joe Smith",
PhoneNumber = "123=123=1234" };
Обратите внимание, что объявление анонимного типа использует инициализаторы объектов (см. предыдущее обсуждение) для определения объекта. Большое отличие состоит в том, что после объявления переменной (или после ключевого слова New) отсутствует строгая типизация. Компилятор создаст для вас анонимный тип со свойствами Name и PhoneNumber.
В Visual Basic имеется также ключевое слово Key. Оно служит для указания, что данное свойство анонимного типа должно использоваться компилятором для дальнейшего определения того, как необходимо обрабатывать объект. Свойства, определенные как Key, используются для определения равенства двух экземпляров анонимного типа. В языке C# эта концепция отсутствует. Вместо этого в C# все свойства интерпретируются как свойства, помеченные Key в языке VB. В VB вы указываете свойство Key следующим образом:
Dim emp = New With {Key .Name = "Joe Smith", _
.PhoneNumber = "123-123-1234"}
Вы можете также создавать анонимные типы при помощи переменных (вместо синтаксиса присваивания свойств). В этих случаях компилятор использует имя переменной в качестве названия свойства, а ее значение — в качестве значения свойства анонимного типа.
Например, в следующем коде переменная Name используется как свойство для анонимного типа.
□ VB:
Dim name As String = "Joe Smith"
Dim emp = New With {name, .PhoneNumber = "123-123-1234"}
□ C#:
string name = "Joe Smith";
var emp = new {name, PhoneNumber = "123=123=1234"};.
t
Программирование в своем коде простых неименованных функций
В последней версии .NET-языков вы можете писать простые функции, которые могут иметь или не иметь названий, выполняться вложенным образом и возвращать единственное значение. Эти функции существуют внутри ваших методов (а не как отдельные функции). Эти функции называются лямбда-выражениями. Полезно понимать лямбда-выражения, поскольку они используются "за кулисами" в запросах LINQ. Однако они допустимы также и вне LINQ.
»
Рассмотрим пример. Предположим, что вы хотите создать простую функцию, которая преобразует температуру из градусов Фаренгейта в градусы Цельсия. Вы можете сделать это в коде на Visual Basic, начав с использования ключевого слова Function. Затем вы можете указать параметры этой функции (в данном случае это значение в градусах Фаренгейта). Наконец, вы пишете выражение, вычисляющее значение, которое можно возвратить из лямбда-выражения. Синтаксис таков:
Difn fahToCel = Function(fahValue As Integer) ( (fahValue - 32) / 1.8)
Синтаксис C# несколько отличается. В языке C# вы должны явно объявить делегат для использования компилятором при преобразовании вашего лямбда-выражения. Конечно, вы объявляете делегат на уровне действия класса. После этого вы можете писать в вашем коде выражение. Для этого вы используете оператор =>. Этот оператор читается как "идет к". Слева от оператора вы указываете тип делегата, название выражения, а затем знак =, за которым следуют любые параметры выражения. Справа от оператора => вы ставите фактическое выражение. Далее показан пример и делегата, и выражения:
// Объявление делегата на уровне класса delegate float del(float f);
// Лямбда-выражение внутри тела метода
del fahToCel = (float fahValue) => (float)((fahValue - 32) / 1.8);
Обратите внимание, что в обоих примерах мы присваивали выражение переменной fahToCel. Таким образом, мы создали делегат (с явным приведением типа к нему в языке С#). Теперь мы можем вызывать переменную как делегат и получать результаты (как показано здесь).
□ VB:
Dim celcius As Single = fahToCel(70)
□ С#:
float celcius = fahToCel(-10);
В Visual Basic мы могли бы написать эту функцию встроенной (без присваивания ее переменной). Мы могли бы написать так:
Console.WriteLine((Function(fahValue As Integer) ((fahValue - 32) / 1.8)) (70))
Обратите внимание в этом последнем примере, что функция объявляется, а затем немедленно вызывается передачей внутрь значения 70 в конце функции.
Язык C# также имеет свои особенности. Здесь вы можете написать внутри вашего лямбда-выражения несколько операторов. Для этого вы помещаете их в фигурные скобки и отделяете точкой с запятой. Следующий пример имеет внутри лямбда-выражения два оператора. Первый создает новое значение; второй выводит его на консоль. Обратите также внимание, что делегат в данном случае должен иметь тип void и что вы по-прежнему должны для выполнения лямбда-выражения его вызвать.
// Объявление делегата на уровне класса delegate void del(float f) ;
del fahToCel = (float fahValue) => { float f =
(float)((fahValue - 32) / 1.8); Console.WriteLine(f.ToString()); }; fahToCel(70);
Лямбда-выражения используются в запросах LINQ для таких операторов, как where, Select и Order by. Например, используя LINQ, вы можете написать следующий оператор:
□ VB:
Dim emps = From emp In db.employees Where(emp.Location = "Redmond")
Select emp
□ C#:
var emps = from emp in db.employees where emp.Location == "Redmond" select emp;
Этот код LINQ преобразуется в лямбда-выражения вроде этих:
□ VB:
Dim emps = From emp In db.employees
.Where(Function(emp) emp.Location = "Redmond")
.Select(Function(emp) emp)
□ C#:
var emps = from emp in db.employees
where (emp => emp.Location == "Redmond" select (emp => emp);