Pull to refresh

Всё новое в C# 3.0 в одной небольшой программе

Reading time4 min
Views791
На улице погода не очень, никуда не поехать, решил создать что то извращённое, больно уж захотелось… Предлагаю ниже код небольшой программы. Что она должна выдать на консоль? Скомпилируйте и проверьте себя...

Для тех кто понижает карму: не нравится пост переходите к другим темам. Он находится в персональном блоге. Комментировать ведь охото, а виртуалов я не создаю, не будьте так суровы…



using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;

namespace Frozik
{
    static class Program
    {
        public static char FirstChar<TInput>(this TInput value)
            where TInput: class
        {
            return value.ToString()[0];
        }

        static void Main()
        {
            var arguments = new List<string> { «arg_0», «temp_z», «arg_1», «arg_2»};

            object locker;

            lock (locker = new object())
            {
                Console.WriteLine(«Started»);

                ((Func<string>)(() =>
                {
                    lock (locker)
                    {
                        var result = string.Empty;

                        foreach (string arg in
                            (from argEntity in arguments
                             where argEntity.StartsWith(«arg_»)
                             select argEntity.Substring(4)))
                        {
                            Console.WriteLine(result += arg.FirstChar<string>());
                        }

                        return result;
                    }
                })).BeginInvoke(
                    (delegate (IAsyncResult result) {
                        Console.WriteLine(
                            new
                            {
                                Lenght =
                                    ((Func<string>)((AsyncResult)result).AsyncDelegate).
                                        EndInvoke(result).Length
                            }.Lenght);
                    }),
                    new object()
                );

                Console.WriteLine(«Finished»);

                Console.ReadKey();
            }

            Console.ReadKey();
        }
    }
}

Ниже даны объяснения, для тех, кому непонятен синтаксис


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;

namespace Frozik
{
    static class Program
    {
        // Создаём расширение для всех ссылочных типов, в моей программе расширение
        // будет применяться только для string'ов. Расширение у меня generic только для того,
        // чтобы побольше запутать.
        // Как работают расширения:
        // К любому стандартному и нестандартному типу можно добавить методы, как будто они
        // были реализованы в самом классе. Далее в программе у меня используется расширение
        // для строки — arg.FirstChar<string>()
        // Расширения обязательно должны быть public static и создаваться в статическом классе
        public static char FirstChar<TInput>(this TInput value)
            // Расширение будет для ссылочных типов — generic типы доступны начиная с C# 2.0 и .Net 2.0
            where TInput: class
        {
            return value.ToString()[0];
        }

        static void Main()
        {
            // Нововведение — за место вызова метода Add можно просто все данные указать как
            // при объявлении массива. Также в данном случае arguments будет типа List<string>,
            // intellisense это всё поймёт и будет корректно работать.
            var arguments = new List<string> { «arg_0», «temp_z», «arg_1», «arg_2»};

            object locker;

            lock (locker = new object())
            {
                Console.WriteLine(«Started»);

                // Лямбда выражение, по сути дела является анонимным делегатом. У стандартного типа
                // Func (функция с возвращаемым параметром) можно также указать входные параметры
                // которые в моём примере не нужны
                // За место лямбда выражения можно было бы создать анонимный делегат
                // (delegate () {
                ((Func<string>)(() =>
                // Если бы стояла задача, мы могли бы написать следующее:
                // Console.WriteLine(((Func<int, int, string>)((x, y) => (x+y).ToString()))(5, 5));
                // Мы бы создали лямбда выражение, которое на вход имеет 2 параметра типа int, а на выходе
                // string, и вызвали бы его с параметрами 5 и 5. Можете попробовать, это выведет 10 на консоль
                // Пример в комментарии выше реализованный с помощью анонимного делегата -
                // Console.WriteLine(((Func<int, int, string>)(delegate(int x, int y) { return (x + y).ToString(); }))(5, 5));
                {
                    // Лямбда выражение имеет доступ до локальных переменных, которые были
                    // определены в методе родителя.
                    lock (locker)
                    {
                        // В данном случае result у нас будет типа string
                        var result = string.Empty;

                        foreach (string arg in
                            // Выражение Linq. Результат будет — IEnumerable<string>
                            // Мы ищем в arguments все значения, которые начинаются на «arg_»
                            // а в качестве результата берём только Substring(4) от каждого найденого
                            // результата. IEnumerable<string> легко превратить в List<string> или
                            // string[], достаточно просто вконце дописать .ToList() или ToArray()
                            // Также это выражение аналогично следующему -
                            // arguments.Where((argEntity) => argEntity.StartsWith(«arg_»)).
                            //     Select((argEntity) => argEntity.Substring(4))
                            // Подробней можете посмотреть здесь — msdn2.microsoft.com/en-us/vcsharp/aa336746.aspx
                            (from argEntity in arguments
                             where argEntity.StartsWith(«arg_»)
                             select argEntity.Substring(4)))
                        {
                            // Складываем первые буквы строк и возвращаем результат сложения
                            Console.WriteLine(result += arg.FirstChar<string>());
                        }

                        return result;
                    }
                })).
                // Так как лямбда выражение может быть анонимным делегатом, то значит мы можем вызвать его
                // в отдельном потоке
                BeginInvoke(
                    // Создаем анонимный делегат, который будет вызван, когда запрос выполнится,
                    // за место этого можно было бы написать лямбда выражение
                    // (result) => {
                    (delegate (IAsyncResult result) {
                        Console.WriteLine(
                            // Создание типа на лету, у которого будет одно свойство Length,
                            // присутствует здесь только для того, чтобы побольше запутать
                            new
                            {
                                Lenght = ((Func<string>)((AsyncResult)result).AsyncDelegate).
                                    EndInvoke(result).Length
                            }.
                            // Получение свойства Lenght у анонимного типа
                            Lenght);
                    }),
                    new object()
                );

                Console.WriteLine(«Finished»);

                Console.ReadKey();
            }

            Console.ReadKey();
        }
    }
}

// Остались одни блокировки, но их объяснять не буду, это все должны знать ;-)
Tags:
Hubs:
Total votes 10: ↑7 and ↓3+4
Comments12

Articles