Где CLR-определенные методы, такие как [delegate].Метод BeginInvoke документально? [закрытый]

[EDIT, полностью перефразировано:] похоже, мой вопрос был действительно плохо сформулирован и плохо принят. Поэтому я надеюсь, что это полное перефразирование помогает...

MSDN ясно указывает: управление.BeginInvoke () выполняет делегат в потоке, на котором был создан дескриптор элемента управления, обычно это будет поток GUI. И диспетчер.BeginInvoke () будет работать в потоке, где был объект диспетчера создан. Это будет любая нить, созданная мной.

но для делегатов " the CLR автоматически определяет BeginInvoke и EndInvoke" и эти вызовы выполняются вместо ThreadPool-thread. Помимо этого немного удивительного поведения, мне интересно, как я могу найти спецификации всех функций, которые автоматически реализуются.

например: Intelli-sense показывает, что мой делегат имеет DynamicInvoke(). Класс

2 ответов


Управление.Begin/End / Invoke() и диспетчер.Методы Begin/End/Invoke() имеют идентичные имена и несколько схожее поведение с методами begin/End/Invoke() делегата, но, безусловно, лучше отказаться от идеи, что они одинаковы. Наиболее важным отличием является то, что методы делегата являются type-safe, что-то, что полностью отсутствует в версиях Control и Dispatcher. Поведение среды выполнения также сильно отличается.

правила, которые управляют a делегат подробно прописан в спецификации CLI,ECMA 335 Глава II.14.6. Лучше всего прочитать главу, я просто дам краткий обзор.

объявление делегата преобразуется в класс, который наследует от MulticastDelegate (не делегирует, как указано в спецификации CLI). Этот класс всегда имеет ровно 4 члена, их реализация во время выполнения обеспечивается CLR:

  • конструктор, который принимает объект и IntPtr. Объект это делегат.Target, IntPtr-это адрес целевого метода, делегат.Метод. Эти члены используются позже при вызове делегата, свойство Target предоставляет этой ссылка Если метод, к которому привязан делегат, является методом экземпляра, null для статического метода. Свойство Method определяет, какой метод вызывается. Вы не указываете эти аргументы напрямую, компилятор предоставляет их при использовании оператора new или подписаться на обработчик событий с оператором+=. С большим количеством синтаксического сахара в случае событий вам не нужно использовать new явного оператора.

  • метод Invoke (). Аргументы метода динамически генерируются и соответствуют объявлению делегата. Вызов метода Invoke () запускает целевой метод делегата в том же потоке, a синхронно звонок. Вы редко используете его в C#, вы просто используете синтаксический сахар, который позволяет объекту делегата быть вызывается только с помощью имени объекта, за которым следуют круглые скобки.

  • метод BeginInvoke (), предоставляет способ сделать асинхронные звонок. Метод быстро завершается, пока целевой метод занят выполнением, подобно ThreadPool.QueueUserWorkItem, но с безопасными для типа аргументами. Возвращаемый тип всегда является системным.IAsyncResult, используется, чтобы узнать, когда асинхронный вызов завершен и передан методу EndInvoke (). Первый аргумент - опционная система.Объект делегата AsyncCallback, его цель будет автоматически вызываться при завершении асинхронного вызова. Второй аргумент является необязательным объект, он будет передан как есть обратному вызову, полезно отслеживать состояние. Дополнительные аргументы генерируются динамически и соответствуют объявлению делегата.

  • метод EndInvoke (). Требуется один аргумент типа IAsyncResult, вы должны передать тот, который вы получили от BeginInvoke (). Он завершает асинхронный вызов и освобождает ресурсы.

любые дополнительные методы, которые вы видите на объекте делегата, являются теми, которые наследуются от базовых классов, MulticastDelegate и Delegate. Как DynamicInvoke () и GetObjectData ().

асинхронные вызовы являются сложными, и вам редко нужно их использовать. На самом деле они недоступны.Цели NETCore, такие как Silverlight. Целевой метод делегата выполняется в произвольном пуле потоков нить, как и Тредпул.QueueUserWorkItem () делает. Любое необработанное исключение, которое он может бросить, захватывается и завершает поток, но не вашу программу. Вы должны вызов EndInvoke (), не делая этого, вызовет утечку ресурсов в течение 10 минут. Если целевой метод вызвал исключение, то он будет повторно вызван при вызове EndInvoke (). У вас нет контроля над потоком пула потоков, его невозможно отменить или прервать. Классы задач или потоков лучше альтернативы.

MSDN актуально, методы типа делегата являются не документально. Предполагается, что вы знаете, что они делают и как они выглядят из спецификации и объявления делегата.


в соответствии с предметом вашего вопроса ответом будут эти жирные строки. MSDN может быть не лучше, но это хорошо, хотя:)

Джеффри Рихтер написал о том, что вы задали в своем вопросе выше. У него есть эта статья в журнале MSDN. http://msdn.microsoft.com/en-us/magazine/cc164139.aspx Эта статья покажет вам реализацию того, как на самом деле (может быть, не на самом деле, но очень близко к) этот BeginInvoke и EndInvoke фактически реализуется в .ЧИСТАЯ СРЕДА CLR. Инвестируйте некоторое время в эту статью, и после этого я не думаю, что теперь вам нужно читать вперед. Джеффри Рихтер также очень хорошо объяснил это в своей книге CLR через C#.

большинство приложений пользовательского интерфейса однопоточны. Доступ к элементам управления пользовательского интерфейса можно получить только с помощью потока, с помощью которого они были созданы.

для достижения этого контроля.Вызов существует в Winforms. Он автоматически вызовет ваш код на поток пользовательского интерфейса. В мире WPF у нас нет контроля.Взывать. В WPF вместо управления у нас есть диспетчер.

теперь делегировать против делегата. Ханс Пассант предоставил очень хороший ответ.

делегат, как указано в MSDN, является классом. Давайте возьмем этот код (взятый из msdnhttp://msdn.microsoft.com/en-us/library/ms173171 (v=против 80).aspx )

public delegate int PerformCalculation(int x, int y);

как вы можете видеть здесь у нас есть делегат (заметьте с маленькой "д"). Это ключевое слово для определения делегата или, проще говоря, для определения переменной PerformCalculation, которая фактически содержит ссылку на метод.

Я думаю, вы уже знаете об этом, но только для полноты.

теперь использовать эту переменную и вызвать метод, используя такой код:

using System;
// Declare delegate -- defines required signature:
delegate void SampleDelegate(string message);

class TestDelegate
{
    private void CallMeUsingDelegate(string m_param)
    {
        Console.WriteLine("Called me using parameter - " + m_param);
    }

    public static void Main(string[] args)
    {
        // Here is the Code that uses the delegate defined above.
        SampleDelegate sd = new SampleDelegate(CallMeUsingDelegate);
        sd.Invoke("FromMain");
    }
}

теперь для вызова метода нужно напишите полный метод как метод CallMeUsingDelegate выше. В C# это анонимные методы который можно использовать для вызова метода, фактически не записывая его как метод.

таким образом, код выше также может быть записан как

использование системы; // Declare delegate -- определяет требуемую подпись: делегировать void SampleDelegate (строковое сообщение);

class TestDelegate
{
    public static void Main(string[] args)
    {
        // Here is the Code that uses the delegate defined above.
        SampleDelegate sd = delegate(param) {
                        Console.WriteLine("Called me using parameter - " + param);
                    };

        sd.Invoke("FromMain");
    }
}

это делает ту же работу, что и приведенный выше код. Но теперь нам нужно писать меньше кода. Этот компилятор создаст идентичный IL-код для обеих версий выше. Но в случае 2, новый метод будет иметь имя автоматически генерируется компилятором.

когда дело доходит до BeginInvoke и EndInvoke, они используются для асинхронного вызова методов. Это делается с помощью threadpool, который доступен с CLR.

в основном, что происходит, вы называете метод с помощью

IAsyncResult ar = sd.BeginInvoke(CallMeUsingDelegate, callMeOnCompletion, sd);

здесь делегат метод, который вы вызываете. Что произойдет, так это Поток вашей программы вызовет метод BeginInvoke, который будет внутренне вызывать метод, указанный в параметре Delegate в потоке ThreadPool среды CLR. Затем программа продолжает работать и возвращает объект, реализующий интерфейс IAsyncResult. Этот объект можно использовать для запроса о ходе выполнения задачи, вызываемой с помощью делегата ( обратите внимание, что делегат sd передается как параметр 3 ).

метод CallMeUsingDelegate вызывается в отдельном потоке (ThreadPool). Когда задача будет завершена, ThreadPool вызовет метод обратного вызова, указанный как 2 параметра.

глядя на все это, вы можете подумать, зачем нам нужен EndInvoke???

Ну, это потому, что если вы не вызываете EndInvoke, пул CLR будет содержать ссылку на эту операцию, и вы будете пропускать некоторую память. Поэтому всегда рекомендуется вызывать EndInvoke в указанном методе обратного вызова.

Я надеюсь, что теперь это очищает (не все) но кое-какие мысли.