如何从Action返回值

kaw*_*awa 2 .net c# delegates

我有代理测试功能.在它里面我有一个catch块,并且在指定的时间(TIMEOUT)之后如果代理不好我返回一个假标志.问题是,即使没有例外,每10次函数会挂起一次.实际上HttpWebResponse.Timeout不能正常工作(或者它可能会工作,但我不知道如何使用它).所以SO用户给了我这个解决方案:

public class TimeoutInvoker
{
    public static void Run(Action action, int timeout)
    {
        var waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
        AsyncCallback callback = ar => waitHandle.Set();
        action.BeginInvoke(callback, null);

        if (!waitHandle.WaitOne(timeout))
            throw new TimeoutException("Timeout.");
    }
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

TimeoutInvoker.Run(()=>ProxyIsGood(ip, port));
Run Code Online (Sandbox Code Playgroud)

问题是我需要像这样使用它,返回值:

while( !(TimeoutInvoker.Run(()=>ProxyIsGood(ip, port)) )
{
    reset_stuff();
}
Run Code Online (Sandbox Code Playgroud)

那么如何修改TimeoutInvoker呢?

slo*_*oth 5

您必须调用EndInvoke以检索异步调用的结果.

将您的班级更改为:

public class TimeoutInvoker
{
    public static TResult Run<TResult>(Func<TResult> action, int timeout)
    {
        var waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
        AsyncCallback callback = ar => waitHandle.Set();

        IAsyncResult result = action.BeginInvoke(callback, null);

        if (!waitHandle.WaitOne(timeout))
            throw new TimeoutException("Timeout.");

        return action.EndInvoke(result);
    }
}
Run Code Online (Sandbox Code Playgroud)

或使用TaskTask.Wait:

public class TimeoutInvoker
{
    public static TResult Run<TResult>(Func<TResult> action, int timeout)
    {
        var task = Task.Factory.StartNew(action);

        if (task.Wait(timeout)) 
            return task.Result;

        throw new TimeoutException("Timeout.");
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这只会在超时(并且不使用a CancellationToken)时抛出异常.