threadInvoke.Run(methodToCall, ...
компилятор создаёт статический делегат GenericDelegate соотвествующий methodToCall.
ThreadInvoke выполняет ожидание завершения работы делегата, и передаёт управление назад в асинхронный поток. Объявлено 2 типа GenericDelegate - возвращающий назад значение и не возвращающий.
Пример использования класс Test.
Класс ThreadInvoke содержит рабочий код.
class Test
{
ThreadInvoke threadInvoke = new ThreadInvoke();
/// <summary>
/// Метод который будет вызван из асинхронного потока
/// </summary>
/// <param name="msg">Параметр переданный из асинъронного потока</param>
void methodToCall(string msg)
{
System.Windows.Forms.MessageBox.Show("Сообщение из асинхронного потока: " + msg);
}
/// <summary>
/// Метод который будет вызван из асинхронного потока
/// </summary>
/// <param name="msg">Параметр переданный из асинъронного потока</param>
/// <returns>Возвращает в асинхронный поток число</returns>
int methodToCall2(string msg)
{
return msg.Length;
}
/// <summary>
/// Точка входа в пример
/// </summary>
public void start()
{
new System.Threading.Thread(new System.Threading.ThreadStart(asyncMethod)).Start();
}
void asyncMethod()
{
// получение длины текста используя другой поток
int len = threadInvoke.Run<string, int>(methodToCall2, "асинхронный поток");
// передача параметра без ответа
threadInvoke.Run(methodToCall, "асинхронный поток получил значение " + len);
// Функиця methodToCall отработала т.к. threadInvoke.Run выполняет ожидание
}
}
/// <summary>
/// Привязывается к потоку и вызывает методы с ожиданием в другом потоке
/// </summary>
/// <typeparam name="TIn">Тип входящего параметра</typeparam>
/// <typeparam name="TOut">Тип выходящего параметра</typeparam>
public class ThreadInvoke
{
static EventWaitHandle thread = new AutoResetEvent(false);
SynchronizationContext sync;
public ThreadInvoke()
{
sync = AsyncOperationManager.SynchronizationContext; //сопоставил контекст
}
/// <summary>
/// Поменять рабочий поток на текущий
/// </summary>
public void ChangeThread()
{
sync = AsyncOperationManager.SynchronizationContext; //сопоставил контекст
}
/// <summary>
/// Поменять рабочий поток на контекст указанного потока
/// </summary>
/// <param name="context"></param>
public void ChangeThread(SynchronizationContext context)
{
sync = context; //сопоставил контекст
}
//SendOrPostCallback callback = new SendOrPostCallback(threadBody);
object locker = new object();
/// <summary>
/// Выполняет делегат на потоке и возвращает результат
/// </summary>
/// <typeparam name="TInput">Тип входящего значения</typeparam>
/// <typeparam name="TOutput">Тип выходящего значения</typeparam>
/// <param name="method">Делегат для запуска</param>
/// <param name="param">Передаваемый параметр</param>
/// <returns></returns>
public TOutput Run<TInput, TOutput>(GenericDelegate<TInput, TOutput> method, TInput param)
{
lock (locker)
{
EventWaitHandle thread = new AutoResetEvent(false);
//thread.Reset(); // включаю ожидание
Container1<TInput, TOutput> container = new Container1<TInput, TOutput>(param, method);
sync.Post(delegate(object perem)
{
Container1<TInput, TOutput> cont = perem as Container1<TInput, TOutput>;
try
{
object ret = cont.Method.Invoke(cont.InValue);
try
{
cont.OutValue = (TOutput)ret;
}
catch (Exception)
{
throw new Exception("Ошибка преобразрвания возвращённого значения к типу " + typeof(TOutput).ToString());
}
}
catch (Exception ex)
{
cont.Error = ex;
}
finally
{
thread.Set();// конец операции
}
}, container);
thread.WaitOne(-1);//жду когда окончится
if (container.Error != null) throw container.Error;
return container.OutValue;
}
}
public void Run<TInput>(GenericDelegate<TInput> method, TInput param)
{
lock (locker)
{
EventWaitHandle thread = new AutoResetEvent(false);
//thread.Reset(); // включаю ожидание
Container2<TInput> container = new Container2<TInput>(param, method);
sync.Post(delegate(object perem)
{
Container2<TInput> cont = perem as Container2<TInput>;
try
{
cont.Method.Invoke(cont.InValue);
}
catch (Exception ex)
{
cont.Error = ex;
}
finally
{
thread.Set();// конец операции
}
}, container);
thread.WaitOne(-1);//жду когда окончится
if (container.Error != null) throw container.Error;
}
}
class Container1<TIn1, TOut1>
{
public Container1(TIn1 inValue, GenericDelegate<TIn1, TOut1> method)
{
InValue = inValue;
Method = method;
}
public TIn1 InValue { get; private set; }
public TOut1 OutValue { get; set; }
public Exception Error { get; set; }
public GenericDelegate<TIn1, TOut1> Method { get; private set; }
}
class Container2<TIn1>
{
public Container2(TIn1 inValue, GenericDelegate<TIn1> method)
{
InValue = inValue;
Method = method;
}
public TIn1 InValue { get; private set; }
public Exception Error { get; set; }
public GenericDelegate<TIn1> Method { get; private set; }
}
}
/// <summary>
/// Делегат для запуска чего-либо на другом потоке
/// </summary>
/// <typeparam name="TInput">Тип входящего значения</typeparam>
/// <typeparam name="TOutput">Тип выходящего значения</typeparam>
/// <param name="perem">Параметр передаваемый в метод</param>
/// <returns>Возвращаемое значение</returns>
public delegate TOutput GenericDelegate<TInput, TOutput>(TInput perem);
public delegate void GenericDelegate<TInput>(TInput perem);
Комментариев нет:
Отправить комментарий