使用BeginInvoke和EndInvoke时,如何避免传递/存储代理? [英] How can I avoid having to pass around/store a delegate when using BeginInvoke and EndInvoke?

查看:147
本文介绍了使用BeginInvoke和EndInvoke时,如何避免传递/存储代理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

修改:将实际问题移动到顶端。

Edit: Moved the actual question to the top.

更新:Microsoft发现了一个示例,

Update: Found an example by Microsoft, tucked on some more code at the end.

我的问题是这些:


  1. 在同一个委托实例上调用多个BeginInvoke调用是安全的,还是为每个正在运行的方法调用构建一个新的委托实例?

  2. 如果我必须构建新的有些方法可以让IAsyncResult值保留原来的代理?

  3. 有没有其他更好的方式来添加异步支持到我的类,而不是使用代理?

更多信息如下。

我在添加异步支持我的班级,以为我会这么简单。

I am adding asynchronous support to a class of mine, and thought I'd do it simple.

参加这个课程:

public class Calculator
{
    public Int32 Add(Int32 a, Int32 b)
    {
        return a + b;
    }
}

我以为我可以这样做:

public class Calculator
{
    private delegate Int32 AddDelegate(Int32 a, Int32 b);
    public Int32 Add(Int32 a, Int32 b)
    {
        return a + b;
    }

    public IAsyncResult BeginAdd(Int32 a, Int32 b,
        AsyncCallback callback, Object obj)
    {
        return new AddDelegate(Add).BeginInvoke(a, b, callback, obj);
    }

    public Int32 EndAdd(IAsyncResult ar)
    {
        return new AddDelegate(Add).EndInvoke(ar);
    }
}

这不行,因为这两种方法构造自己的委托对象,并且.EndInvoke调用检查我的调用它的代理实例是否与我原来称为BeginInvoke的相同。

This doesn't work, as the two methods each construct their own delegate object, and the .EndInvoke call checks to see if the delegate instance i call it on is the same as the one I originally called BeginInvoke on.

处理这个最简单的方法是将参考存储到变量中,如下所示:

The simplest way to handle this would be to just store a reference into a variable, like this:

public class Calculator
{
    private delegate Int32 AddDelegate(Int32 a, Int32 b);
    private AddDelegate _Add;

    public Calculator()
    {
        _Add = new AddDelegate(Add);
    }

    public Int32 Add(Int32 a, Int32 b)
    {
        return a + b;
    }

    public IAsyncResult BeginAdd(Int32 a, Int32 b,
        AsyncCallback callback, Object obj)
    {
        return _Add.BeginInvoke(a, b, callback, obj);
    }

    public Int32 EndAdd(IAsyncResult ar)
    {
        return _Add.EndInvoke(ar);
    }
}

请注意,我完全意识到允许同一个类的多个实例方法同时执行,关于共享状态等。

Note that I'm fully aware of problems with allowing multiple instance methods on the same class to execute at the same time, with regards to shared state, etc.

更新:我在这里发现这个例子是由Microsoft在异步代理编程示例。它显示将 IAsyncResult 引用转发到 AsyncResult 对象,然后我可以得到原始委托实例通过 AsyncDelegate 属性

Update: I found this example here by Microsoft on Asynchronous Delegates Programming Sample. It shows casting the IAsyncResult reference back to an AsyncResult object, and then I can get the original delegate instance through the AsyncDelegate property.

这是一个安全的方法吗?

Is this a safe approach?

换句话说,以下类是否正常?

In other words, is the following class fine?

public class Calculator
{
    private delegate Int32 AddDelegate(Int32 a, Int32 b);

    public Int32 Add(Int32 a, Int32 b)
    {
        return a + b;
    }

    public IAsyncResult BeginAdd(Int32 a, Int32 b, AsyncCallback callback, Object obj)
    {
        return new AddDelegate(Add).BeginInvoke(a, b, callback, obj);
    }

    public Int32 EndAdd(IAsyncResult ar)
    {
        AddDelegate del = (AddDelegate)((AsyncResult)ar).AsyncDelegate;
        return del.EndInvoke(ar);
    }
}


推荐答案

:如果你只是代表委托本身 - 我想你可以这么做:

if you just mean the delegate itself - I think you can just do:

public Int32 EndAdd(IAsyncResult ar)
{
    var d = (AddDelegate)((AsyncResult)ar).AsyncDelegate;
    return d.EndInvoke(ar);
}






你可以随时捕获它进入代表像这样: Async without the Pain ,这让你只需使用 Action 回调(或 Action< T> )。


You could always capture it into the delegate; something like here: Async without the Pain, which lets you just use an Action callback (or Action<T>).

其他常见的模式涉及回调的事件,也许 ThreadPool.QueueUserWorkItem ;比 IAsyncResult 简单得多。

Other common patterns involve events for the callback, and perhaps ThreadPool.QueueUserWorkItem; a lot simpler than IAsyncResult.

将所有这一切放在一起;这里有一个例子,即调用者和代码都不需要关注 IAsyncResult

Putting all this together; here's an example where neither the caller nor the code needs to get stressed about IAsyncResult:

using System;
using System.Runtime.Remoting.Messaging;
public class Calculator
{
    private delegate Int32 AddDelegate(Int32 a, Int32 b);
    public Int32 Add(Int32 a, Int32 b)
    {
        return a + b;
    }

    public IAsyncResult BeginAdd(Int32 a, Int32 b,
        AsyncCallback callback, Object obj)
    {
        return new AddDelegate(Add).BeginInvoke(a, b, callback, obj);
    }

    public Int32 EndAdd(IAsyncResult ar)
    {
        var d = (AddDelegate)((AsyncResult)ar).AsyncDelegate;
        return d.EndInvoke(ar);
    }
}
static class Program
{
    static void Main()
    {
        Calculator calc = new Calculator();
        int x = 1, y = 2;
        Async.Run<int>(
            (ac,o)=>calc.BeginAdd(x,y,ac,o),
            calc.EndAdd, result =>
            {
                Console.WriteLine(result());
            });
        Console.ReadLine();
    }
}
static class Async
{
    public static void Run<T>(
    Func<AsyncCallback, object, IAsyncResult> begin,
    Func<IAsyncResult, T> end,
    Action<Func<T>> callback)
    {
        begin(ar =>
        {
            T result;
            try
            {
                result = end(ar); // ensure end called
                callback(() => result);
            }
            catch (Exception ex)
            {
                callback(() => { throw ex; });
            }
        }, null);
    }
}

这篇关于使用BeginInvoke和EndInvoke时,如何避免传递/存储代理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆