我如何避免使用的BeginInvoke和EndInvoke时绕过/存储的委托? [英] How can I avoid having to pass around/store a delegate when using BeginInvoke and EndInvoke?

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

问题描述

修改:移动到顶部的实际问题。

更新:发现微软为例,在卷起在年底一些code

我的问题是:


  1. 它是安全的调用多个BeginInvoke的上相同的委托实例调用,还是我要建立一个新的委托实例每个飞行方法调用?

  2. 如果我有构造新的记录每一个,有一些方法来获得原始委托持币观望的IAsyncResult价值?

  3. 有一些其他的,更好的,方式异步支持我的课比添加使用委托?

更多信息如下:

我加入一类矿井异步支持,我想我会做简单的。

就拿这个类:

 公共类计算器
{
    公众的Int32添加(的Int32一个,的Int32 B)
    {
        返回A + B;
    }
}

我以为我可以简单地这样做:

 公共类计算器
{
    私人委托的Int32 AddDelegate(一的Int32,的Int32 B);
    公众的Int32添加(的Int32一个,的Int32 B)
    {
        返回A + B;
    }    公众的IAsyncResult BeginAdd(一的Int32,的Int32 B,
        AsyncCallback的回调,obj对象)
    {
        返回新AddDelegate(添加).BeginInvoke(A,B,回调,OBJ);
    }    公众的Int32 EndAdd(IAsyncResult的AR)
    {
        返回新AddDelegate(添加).EndInvoke(AR);
    }
}

这是不行的,因为这两个方法都构建自己的委托对象,并调用.EndInvoke检查是否委托实例我把它上是一样的一个我原来叫上的BeginInvoke。

来处理这将是只是一个参考存储到一个变量,这样最简单的方式:

 公共类计算器
{
    私人委托的Int32 AddDelegate(一的Int32,的Int32 B);
    私人AddDelegate _add;    公共计算器()
    {
        _add =新AddDelegate(添加);
    }    公众的Int32添加(的Int32一个,的Int32 B)
    {
        返回A + B;
    }    公众的IAsyncResult BeginAdd(一的Int32,的Int32 B,
        AsyncCallback的回调,obj对象)
    {
        返回_Add.BeginInvoke(A,B,回调,OBJ);
    }    公众的Int32 EndAdd(IAsyncResult的AR)
    {
        返回_Add.EndInvoke(AR);
    }
}

请注意,我是完全明白的问题,允许在同一类的多个实例方法在同一时间执行,关于共享状态,等等。


更新:我发现这里的这个例子微软的异步委托编程示例。这表明铸造 IAsyncResult的参考回到一个的 AsyncResult 对象,然后我可以得到原来的委托例如通过<一个href=\"http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.asyncresult.asyncdelegate.aspx\"相对=nofollow> AsyncDelegate 属性。

这是一种安全的方法?

在换句话说,就是下面的类罚款?

 公共类计算器
{
    私人委托的Int32 AddDelegate(一的Int32,的Int32 B);    公众的Int32添加(的Int32一个,的Int32 B)
    {
        返回A + B;
    }    公众的IAsyncResult BeginAdd(一的Int32,的Int32 B,AsyncCallback的回调,obj对象)
    {
        返回新AddDelegate(添加).BeginInvoke(A,B,回调,OBJ);
    }    公众的Int32 EndAdd(IAsyncResult的AR)
    {
        AddDelegate德尔=(AddDelegate)((AsyncResult)AR).AsyncDelegate;
        返回del.EndInvoke(AR);
    }
}


解决方案

编辑:如果你只是意味着代表本身 - 我的认为的你可以这样做:

 公众的Int32 EndAdd(IAsyncResult的AR)
{
    变种D =(AddDelegate)((AsyncResult)AR).AsyncDelegate;
    返回d.EndInvoke(AR);
}


您可以随时捕捉到它的代表;像在这里:异步无疼痛,它可以让你只使用动作的回调(或动作&LT; T&GT; )。

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


放在一起这一切;这里的地方需要得到强调有关既不呼叫者也不是code为例的IAsyncResult

 使用系统;
使用System.Runtime.Remoting.Messaging;
公共类计算器
{
    私人委托的Int32 AddDelegate(一的Int32,的Int32 B);
    公众的Int32添加(的Int32一个,的Int32 B)
    {
        返回A + B;
    }    公众的IAsyncResult BeginAdd(一的Int32,的Int32 B,
        AsyncCallback的回调,obj对象)
    {
        返回新AddDelegate(添加).BeginInvoke(A,B,回调,OBJ);
    }    公众的Int32 EndAdd(IAsyncResult的AR)
    {
        变种D =(AddDelegate)((AsyncResult)AR).AsyncDelegate;
        返回d.EndInvoke(AR);
    }
}
静态类节目
{
    静态无效的主要()
    {
        计算器计算值=新的计算器();
        INT X = 1,Y = 2;
        Async.Run&LT; INT&GT;(
            (AC,0)=&GT; calc.BeginAdd(X,Y,交流,O),
            calc.EndAdd,结果=&GT;
            {
                Console.WriteLine(结果());
            });
        到Console.ReadLine();
    }
}
静态类异步
{
    公共静态无效润LT; T&GT;(
    FUNC&LT;的AsyncCallback,对象,IAsyncResult的&GT;开始,
    FUNC&LT; IAsyncResult的,T&GT;结束,
    动作&LT;&Func键LT; T&GT;&GT;回电话)
    {
        开始(AR =&GT;
        {
            Ť结果;
            尝试
            {
                结果=结束(AR); //确保到底叫什么
                回调(()=&GT;结果);
            }
            赶上(异常前)
            {
                回调(()=&GT; {抛出前;});
            }
        }, 空值);
    }
}

Edit: Moved the actual question to the top.

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

My questions are these:

  1. Is it safe to call multiple BeginInvoke calls on the same delegate instance, or do I have to construct a new delegate instance for each in-flight method call?
  2. If I have to construct new instances for each, is there some way to get hold of the original delegate out of the IAsyncResult value?
  3. Is there some other, better, way to add asynchronous support to my class than using delegates?

More info follows.

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

Take this class:

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

I thought I could simply do this:

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);
    }
}

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.


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);
    }
}

解决方案

Edit: 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);
}


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>).

Other common patterns involve events for the callback, and perhaps ThreadPool.QueueUserWorkItem; a lot simpler than 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天全站免登陆