Академический Документы
Профессиональный Документы
Культура Документы
слово3
слово3
1 string[] teams = {"Бавария", "Боруссия", "Реал Мадрид", "Манчестер Сити", "ПСЖ", "
2
3 var selectedTeams = from t in teams // определяем каждый объект из teams как t
4 where t.ToUpper().StartsWith("Б") //фильтрация по критерию
5 orderby t // упорядочиваем по возрастанию
6 select t; // выбираем объект
7
8 foreach (string s in selectedTeams)
9 Console.WriteLine(s);
Преимуществом подобных запросов также является и то, что они интуитивно похожи на
запросы языка SQL, хотя и имеют некоторые отличия.
Например:
Не каждый метод расширения имеет аналог среди операторов LINQ, но в этом случае
можно сочетать оба подхода. Например, используем стандартный синтаксис linq и метод
расширения Count(), возвращающий количество элементов в выборке:
Делегаты
Определение делегатов
Делегат Message в качестве возвращаемого типа имеет тип void (то есть ничего не
возвращает) и не принимает никаких параметров. Это значит, что этот делегат может
указывать на любой метод, который не принимает никаких параметров и ничего не
возвращает.
1 class Program
2 {
3 delegate int Operation(int x, int y);
4
static void Main(string[] args)
5
{
6
// присваивание адреса метода через контруктор
7 Operation del = Add; // делегат указывает на метод Add
8 int result = del(4,5); // фактически Add(4, 5)
9 Console.WriteLine(result);
1
0 del = Multiply; // теперь делегат указывает на метод Multiply
1 result = del(4, 5); // фактически Multiply(4, 5)
1 Console.WriteLine(result);
1
2 Console.Read();
1 }
private static int Add(int x, int y)
3
{
1
return x+y;
4 }
1 private static int Multiply (int x, int y)
5
1
6
1
7
1
8
1
9
2
0 {
2 return x * y;
1 }
2 }
2
2
3
2
4
2
5
2
6
В данном случае делегат Operation возвращает значение типа int и имеет два
параметра типа int. Поэтому этому делегату соответствует любой метод, который
возвращает значение типа int и принимает два параметра типа int. В данном случае это
методы Add и Multiply. То есть мы можем присвоить переменной делегата любой из этих
методов и вызывать.
Поскольку делегат принимает два параметра типа int, то при его вызове необходимо
передать значения для этих параметров: del(4,5).
1 class Math
2 {
3 public int Sum(int x, int y) { return x + y; }
}
4
class Program
5
{
6 delegate int Operation(int x, int y);
7
8 static void Main(string[] args)
9 {
1
0
1
1
1
2
1 Math math = new Math();
Operation del = math.Sum;
3
int result = del(4, 5); // math.Sum(4, 5)
1
Console.WriteLine(result); // 9
4
1 Console.Read();
5 }
1 }
6
1
7
1
8
Присвоение ссылки на метод
Выше переменной делегата напрямую присваивался метод. Есть еще один способ -
создание объекта делегата с помощью конструктора, в который передается нужный
метод:
1
2
3 class Program
4 {
5 delegate int Operation(int x, int y);
6
7 static void Main(string[] args)
8 {
9 Operation del = Add;
1 Operation del2 = new Operation(Add);
0
1 Console.Read();
}
1
private static int Add(int x, int y) { return x + y; }
1
}
2
1
3
Как было написано выше, методы соответствуют делегату, если они имеют один и тот
же возвращаемый тип и один и тот же набор параметров. Но надо учитывать, что во
внимание также принимаются модификаторы ref и out. Например, пусть у нас есть
делегат:
Здесь метод SomeMethod2 имеет другой возвращаемый тип, отличный от типа делегата.
SomeMethod3 имеет другой набор параметров. Параметры SomeMethod4 и
SomeMethod5 также отличаются от параметров делегата, поскольку имеют
модификаторы ref и out.
1 class Program
2 {
3 delegate void Message();
4
static void Main(string[] args)
5
{
6
Message mes1 = Hello;
7 mes1 += HowAreYou; // теперь mes1 указывает на два метода
8 mes1(); // вызываются оба метода - Hello и HowAreYou
9 Console.Read();
1 }
0 private static void Hello()
1 {
1 Console.WriteLine("Hello");
1
2
1
3
1
4
1 }
5 private static void HowAreYou()
1 {
6 Console.WriteLine("How are you?");
1 }
7 }
1
8
1
9
2
0
В данном случае в список вызова делегата mes1 добавляются два метода - Hello и
HowAreYou. И при вызове mes1 вызываются сразу оба этих метода.
При добавлении делегатов следует учитывать, что мы можем добавить ссылку на один
и тот же метод несколько раз, и в списке вызова делегата тогда будет несколько
ссылок на один и то же метод. Соответственно при вызове делегата добавленный метод
будет вызываться столько раз, сколько он был добавлен:
Консольный вывод:
Hello
Hello
Hello
Подобным образом мы можем удалять методы из делегата с помощью операции -=:
1
2 static void Main(string[] args)
3 {
Message mes1 = Hello;
4
mes1 += HowAreYou;
5
mes1(); // вызываются все методы из mes1
6 mes1 -= HowAreYou; // удаляем метод HowAreYou
7 mes1(); // вызывается метод Hello
8
9 Console.Read();
1 }
0
При удалении следует учитывать, что если делегат содержит несколько ссылок на один
и тот же метод, то операция -= начинает поиск с конца списка вызова делегата и
удаляет только первое найденное вхождение. Если подобного метода в списке вызова
делегата нет, то операция -= не имеет никакого эффекта.
Объединение делегатов
1 class Program
2 {
3 delegate void Message();
4
static void Main(string[] args)
5
{
6
Message mes1 = Hello;
7 Message mes2 = HowAreYou;
8 Message mes3 = mes1 + mes2; // объединяем делегаты
9 mes3(); // вызываются все методы из mes1 и mes2
1
0 Console.Read();
1 }
1 private static void Hello()
1 {
2 Console.WriteLine("Hello");
}
1
private static void HowAreYou()
3
{
1 Console.WriteLine("How are you?");
4 }
1 }
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
Вызов делегата
В примерах выше делегат вызывался как обычный метод. Если делегат принимал
параметры, то при ее вызове для параметров передавались необходимые значения:
1 class Program
2 {
3 delegate int Operation(int x, int y);
delegate void Message();
4
5
static void Main(string[] args)
6
{
7 Message mes = Hello;
8 mes();
9 Operation op = Add;
1 op(3, 4);
0 Console.Read();
1 }
1 private static void Hello() { Console.WriteLine("Hello"); }
1 private static int Add(int x, int y) { return x + y; }
}
2
1
3
1
4
1
5
1
6
1
2
3
4
5 class Program
6 {
7 delegate int Operation(int x, int y);
8 delegate void Message();
9
1 static void Main(string[] args)
{
0
Message mes = Hello;
1
mes.Invoke();
1 Operation op = Add;
1 op.Invoke(3, 4);
2 Console.Read();
1 }
3 private static void Hello() { Console.WriteLine("Hello"); }
1 private static int Add(int x, int y) { return x + y; }
4 }
1
5
1
6
Если делегат принимает параметры, то в метод Invoke передаются значения для этих
параметров.
Следует учитывать, что если делегат пуст, то есть в его списке вызова нет ссылок ни на
один из методов (то есть делегат равен Null), то при вызове такого делегата мы
получим исключение, как, например, в следующем случае:
1
2
3
4
5 class Program
6 {
7 delegate int Operation(int x, int y);
8
9 static void Main(string[] args)
1 {
Operation op = Subtract;
0
op += Multiply;
1
op += Add;
1 Console.WriteLine(op(7, 2)); // Add(7,2) = 9
1 Console.Read();
2 }
1 private static int Add(int x, int y) { return x + y; }
3 private static int Subtract(int x, int y) { return x - y; }
1 private static int Multiply(int x, int y) { return x * y; }
4 }
1
5
1
6
1 class Program
2 {
3 delegate void GetMessage();
4
static void Main(string[] args)
5
6
7
8
9
1
0
1
1
1
2
1
3 {
1 if (DateTime.Now.Hour < 12)
4 {
1 Show_Message(GoodMorning);
}
5
else
1
{
6 Show_Message(GoodEvening);
1 }
7 Console.ReadLine();
1 }
8 private static void Show_Message(GetMessage _del)
1 {
9 _del?.Invoke();
2 }
private static void GoodMorning()
0
{
2
Console.WriteLine("Good Morning");
1 }
2 private static void GoodEvening()
2 {
2 Console.WriteLine("Good Evening");
3 }
2 }
4
2
5
2
6
2
7
2
8
2
9
Обобщенные делегаты
1
2
3
4
5
delegate T Operation<T, K>(K val);
6
7
class Program
8 {
9 static void Main(string[] args)
1 {
0 Operation<decimal, int> op = Square;
1
1 Console.WriteLine(op(5));
1 Console.Read();
2 }
1
3 static decimal Square(int n)
{
1
return n * n;
4
}
1 }
5
1
6
1
7
лямда
Лямбда-выражения представляют упрощенную запись анонимных методов. Лямбда-
выражения позволяют создать емкие лаконичные методы, которые могут возвращать
некоторое значение и которые можно передать в качестве параметров в другие методы.
1 class Program
2 {
3 delegate int Operation(int x, int y);
static void Main(string[] args)
4
5
6 {
Operation operation = (x, y) => x + y;
7
Console.WriteLine(operation(10, 20)); // 30
8
Console.WriteLine(operation(40, 20)); // 60
9 Console.Read();
1 }
0 }
1
1
1
2
3 class Program
4 {
5 delegate int Square(int x); // объявляем делегат, принимающий int и в
static void Main(string[] args)
6
{
7
Square square = i => i * i; // объекту делегата присваивается л
8
9 int z = square(6); // используем делегат
1 Console.WriteLine(z); // выводит число 36
0 Console.Read();
1 }
1 }
1
2
Как видно, из примеров выше, нам необязательно указывать тип параметров у лямбда-
выражения. Однако, нам обязательно нужно указывать тип, если делегат, которому
должно соответствовать лямбда-выражение, имеет параметры с
модификаторами ref и out:
1
2
3 class Program
4 {
5 delegate void ChangeHandler(ref int x);
static void Main(string[] args)
6
{
7
int x = 9;
8 ChangeHandler ch = (ref int n) => n = n * 2;
9 ch(ref x);
1 Console.WriteLine(x); // 18
0 Console.Read();
1 }
1 }
1
2
1 class Program
2 {
3 delegate void Hello(); // делегат без параметров
static void Main(string[] args)
4
5
6
7 {
8 Hello message = () => Show_Message();
9 message();
1 }
0 private static void Show_Message()
1 {
1 Console.WriteLine("Привет мир!");
}
1
}
2
1
3
1 class Program
2 {
3 delegate bool IsEqual(int x);
4
static void Main(string[] args)
5
{
6
int[] integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
7
8 // найдем сумму чисел больше 5
9 int result1 = Sum(integers, x => x > 5);
1 Console.WriteLine(result1); // 30
0
1 // найдем сумму четных чисел
1 int result2 = Sum(integers, x => x % 2 == 0);
1 Console.WriteLine(result2); //20
2
1 Console.Read();
3 }
1
private static int Sum (int[] numbers, IsEqual func)
4
{
1
int result = 0;
5 foreach(int i in numbers)
1 {
6 if (func(i))
1 result += i;
7 }
1 return result;
8
1
9
2
0
2
1
2
2
2
3
2
}
4 }
2
5
2
6
2
7
2
8
2
9
3
0
1 if (func(i))