Как вызвать метод асинхронно?Нужно ли создавать класс, производный от IAsyncResult? - PullRequest
0 голосов
/ 24 июля 2010

Я пытаюсь обернуться вокруг асинхронного вызова методов.

public IDictionary<string, int> DoSomething(string startsWith)
{
    return new Dictionary<string, int>();
}

public IAsyncResult BeginDoSomething(string startsWith, AsyncCallback callback,
                                     object state)
{
    return new Func<string, IDictionary<string, int>>(DoSomething)
           .BeginInvoke(startsWith, callback, state);
}

public IDictionary<string, int> EndDoSomething(IAsyncResult result)
{
    // How to return the IDictionary?!
}

Моя проблема в том, что я понятия не имею, как получить IDictionary в методе EndDoSomething.Я погуглил и увидел, что некоторые люди используют состояние и обратный вызов, в то время как другие создают свой собственный класс, производный от IAsyncResult, возвращают его из Begin и приводят к нему в конце.Это?Или что будет правильным?

Ответы [ 5 ]

1 голос
/ 24 июля 2010

Немного неприятно выглядит, но это должно сделать это (явно не проверено):

public IDictionary<string, int> DoSomething(string startsWith)
{
    return new Dictionary<string, int>();
}

public IAsyncResult BeginDoSomething(string startsWith, AsyncCallback callback,
                                     object state)
{
    var doSomething = new Func<string, IDictionary<string, int>>(DoSomething);

    return doSomething.BeginInvoke(startsWith, callback, new object[] { doSomething, state });
}

public IDictionary<string, int> EndDoSomething(IAsyncResult result)
{
    var doSomething = (Func<string, IDictionary<string, int>>)((object[])result.AsyncState)[0];

    return doSomething.EndInvoke(result);
}
0 голосов
/ 24 июля 2010

Я думаю, что самый простой способ - использовать класс Task<TResult> (добавлен в .NET 4), который наследуется от IAsyncResult:

public IDictionary<string, int> DoSomething(string startsWith) 
{ 
  return new Dictionary<string, int>(); 
} 

public IAsyncResult BeginDoSomething(string startsWith, AsyncCallback callback, 
                                     object state) 
{
  return Task.Factory.StartNew(_ => { return DoSomething(startsWith); }, state);
} 

public IDictionary<string, int> EndDoSomething(IAsyncResult result) 
{
  var task = (Task<IDictionary<string, int>>)result;
  return task.Result;
} 

Не только Task<TResult> реализует IAsyncResult, но и обрабатывает любые ошибки для вызывающей стороны; они поднимаются автоматически при доступе к Task<TResult>.Result.

0 голосов
/ 24 июля 2010

Будет запущено 2 потока: (1) MainThread и (2) рабочий поток, который запускает DoSomething.Поток (2) собирается вызвать ваш обратный вызов, поэтому он не может ничего вернуть.Вместо этого обратный вызов должен получить результат и поместить его в поле.

Затем основной поток может проверить значение этого поля.

Вот пример:

using System;
using System.Collections.Generic;
using System.Threading;

namespace Commons.CLI.Sandbox
{
    class Program
    {
        static void Main(string[] args)
        {
            var myMain = new Program();
            myMain.Run();

            Console.WriteLine("Result: " + myMain.Output["start"] + " on thread: " + Thread.CurrentThread.ManagedThreadId);
            Console.ReadKey();
        }

        public IDictionary<string, int> Output { get; set; }
        private object _outputLock = new object();

        private DoSomethingResultRetriever _methodToCall;

        private ManualResetEvent _waiter;

        public void Run()
        {
            _waiter = new ManualResetEvent(false);

            _methodToCall = DoSomething;
            var asyncResult = BeginDoSomething("start");

            // We need to wait for the other thread to run
            Console.WriteLine(String.Format("Thread {0} is about to wait.", Thread.CurrentThread.ManagedThreadId));

            // Do other things ...

            if (asyncResult.IsCompleted) return;

            _waiter.WaitOne();
        }

        private IAsyncResult BeginDoSomething(string startsWith)
        {
            return _methodToCall.BeginInvoke(startsWith, EndDoSomething, null);
        }

        private void EndDoSomething(IAsyncResult ar)
        {
            lock (_outputLock)
            {
                Output = _methodToCall.EndInvoke(ar);
            }

            _waiter.Set();
        }

        private delegate IDictionary<string, int> DoSomethingResultRetriever(string startsWith);

        private IDictionary<string, int> DoSomething(string startsWith)
        {
            Console.WriteLine("DoSomething on thread: " + Thread.CurrentThread.ManagedThreadId);
            return new Dictionary<string, int>() { { startsWith, 10 } };
        }
    }
}
0 голосов
/ 24 июля 2010

вам нужно создать делегата и вызвать этот делегат асинхронно.

public delegate IDictionary<String, Int> MyDelegate(string s);
MyDelegate delObj = new MyDelegate(DoSomething);
string str = "testString";
delObj.BeginInvoke(str, new AsyncCallback(CallbackMethod), null);

и

private void CallbackMethod(IAsyncResult iresult)
{
//logic
AsyncResult iResult = iresult as AsyncResult;
MyDelegate del = iResult.AsyncDelegate as MyDelegate;
IDictionary<string,int> result = del.EndInvoke(iresult);
}

http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx

не проверено, можно попробоватьи дайте мне знать Спасибо

0 голосов
/ 24 июля 2010

Я думаю, что вы должны смотреть на это с точки зрения вызова синхронного метода асинхронно через делегата.

http://msdn.microsoft.com/en-us/library/22t547yb(v=VS.71).aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...