gpt4 book ai didi

c# - 在使用 BeginInvoke 和 EndInvoke 时如何避免传递/存储委托(delegate)?

转载 作者:太空狗 更新时间:2023-10-30 00:59:03 25 4
gpt4 key购买 nike

编辑:将实际问题移至顶部。

更新:找了一个微软的例子,最后塞了一些代码。

我的问题是:

  1. 对同一个委托(delegate)实例调用多个 BeginInvoke 调用是否安全,或者我是否必须为每个正在进行的方法调用构造一个新的委托(delegate)实例?
  2. 如果我必须为每个实例构造新实例,是否有某种方法可以从 IAsyncResult 值中获取原始委托(delegate)?
  3. 有没有比使用委托(delegate)更好的方法来为我的类添加异步支持?

更多信息如下。

我正在为我的一个类添加异步支持,我想我会做的很简单。

上这门课:

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

这不起作用,因为这两个方法各自构造自己的委托(delegate)对象,并且 .EndInvoke 调用会检查我调用它的委托(delegate)实例是否与我最初调用 BeginInvoke 的委托(delegate)实例相同。

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

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

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


更新:我在 Microsoft 的 Asynchronous Delegates Programming Sample 上找到了这个示例.它显示类型转换 IAsyncResult引用 AsyncResult对象,然后我可以通过 AsyncDelegate 获取原始委托(delegate)实例属性(property)。

这是一种安全的方法吗?

换句话说,下面的类可以吗?

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

最佳答案

编辑:如果你只是指委托(delegate)本身 - 我认为你可以这样做:

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

您总是可以将其捕获到委托(delegate)中;类似这里:Async without the Pain , 这让你只需要使用 Action回调(或 Action<T> )。

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


将所有这些放在一起;这是一个示例,其中调用者和代码都不需要对 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);
}
}

关于c# - 在使用 BeginInvoke 和 EndInvoke 时如何避免传递/存储委托(delegate)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1484356/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com