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

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



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();
        }
    }
}

// Остались одни блокировки, но их объяснять не буду, это все должны знать ;-)