В соответствии с предметом вашего вопроса ответом будут эти жирные линии. MSDN может быть не лучше, но это хорошо :)
Джеффри Рихтер написал о том, что вы задали в своем вопросе выше. У него есть эта статья в журнале MSDN. http://msdn.microsoft.com/en-us/magazine/cc164139.aspx В этой статье будет показана реализация того, как на самом деле (может быть, не на самом деле, но очень близко) эти BeginInvoke и EndInvoke реализованы в .NET CLR. Потратьте некоторое время на эту статью, и после этого я не думаю, что вам нужно читать дальше. Джеффри Рихтер также очень хорошо объяснил все это в своей книге CLR Via C#.
Большинство приложений пользовательского интерфейса являются однопоточными. Доступ к элементам управления в пользовательском интерфейсе возможен только с помощью потока, в котором они были созданы.
Для этого Control.Invoke существует в Winforms. Он автоматически вызовет ваш код в потоке пользовательского интерфейса. В мире WPF у нас нет Control.Invoke. В WPF у нас есть Dispatcher вместо Control.
Теперь делегат против делегата. Ханс Пассант дал очень хороший ответ.
Поэтому, чтобы немного остановиться на этом, я пишу этот ответ.
Делегат, как упоминалось в MSDN, — это класс. Давайте возьмем этот код (взято из msdn http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx )
public delegate int PerformCalculation(int x, int y);
Как видите, у нас есть делегат (обратите внимание на маленькую букву «d»). Это ключевое слово для определения делегата или, выражаясь простыми словами, это ключевое слово для определения переменной 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# есть анонимные методы, которые можно использовать для вызова метода без необходимости писать его как метод.
Таким образом, приведенный выше код также можно записать как
с помощью системы; // Объявить делегата -- определяет требуемую подпись: delegate void SampleDelegate(string message);
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-код для обеих версий выше. Но во втором случае новый метод будет иметь автоматически сгенерированное компилятором имя.
Когда дело доходит до BeginInvoke и EndInvoke, они используются для асинхронного вызова методов. Это делается с помощью пула потоков, доступного в среде CLR.
В основном, что происходит, вы вызываете метод, используя
IAsyncResult ar = sd.BeginInvoke(CallMeUsingDelegate, callMeOnCompletion, sd);
Здесь Delegate — это метод, который вы вызываете. Что произойдет, так это то, что Thread вашей программы вызовет метод BeginInvoke, который будет внутренне вызывать метод, указанный в параметре Delegate, в потоке CLR ThreadPool. Затем ваша программа продолжает работу и возвращает объект, реализующий интерфейс IAsyncResult. Вы можете использовать этот объект для запроса о ходе выполнения задачи, вызванной с помощью вашего делегата (обратите внимание, что Delegate sd передается как параметр 3).
Метод CallMeUsingDelegate вызывается в отдельном потоке (из ThreadPool). Когда задача завершится, ThreadPool вызовет метод обратного вызова, указанный в качестве параметра 2.
Глядя на все это, вы можете подумать, а зачем нам тогда EndInvoke???
Ну, это потому, что если вы не вызовете EndInvoke, CLR ThreadPool будет содержать ссылку на эту операцию, и вы потеряете часть памяти. Поэтому всегда рекомендуется вызывать EndInvoke в указанном методе обратного вызова.
Я надеюсь, что теперь это проясняет (не все), но некоторые мысли.
person
Dinesh
schedule
24.02.2013