我最近一直在努力学习关于.Net多线程的一切。 (变得更好,但仍然觉得有很多东西需要学习)。现在我专注于APM(异步编程模型),这通常被称为:
//non async method
public int DoSomeWork(int arg)
{
//do something and return result
}
//async version
public IAsyncResult BeginDoSomeWork(int arg, AsyncCallback callback, object @object)
{
}
public int EndDoSomeWork(IAsyncResult result)
{
}
现在,假设我正在编写一些库,并且我希望将此功能公开给任何使用我的API的人,我正在考虑实现此模式的方法。实现IAsyncResult接口是可能的,但它似乎相当复杂。我的问题是,如果使用委托是一个可接受的解决方案。我的意思是:
public class MyClass
{
private Func<int, int> func;
//non async method
public int DoSomeWork(int arg)
{
//do something and return result
}
//async version
public IAsyncResult BeginDoSomeWork(int arg, AsyncCallback callback, object @object)
{
this.func = new Func<int, int>(DoSomeWork);
var asyncResult = this.func.BeginInvoke(arg,callback,object);
return asyncResult;
}
public int EndDoSomeWork(IAsyncResult result)
{
return this.func.EndInvoke(result);
}
}
基本上,每个代表都将BeginXxx和EndXxx功能融入其中。是不是可以利用它,只是暴露IAsyncResult,或者有什么问题,我没想到。
答案 0 :(得分:1)
我认为这是实现APM的一种好方法,但目前每个实例都会出现多个异步调用错误。
为什么不直接将委托用法外部化?
我的意思是,如果您只是将实际逻辑放在课堂上,那么让任何调用您方法的人都可以:
MyClass c = new MyClass();
Func<int, int> f = c.DoSomeWork;
IAsyncResult ar1 = f.BeginInvoke(1, null, null);
IAsyncResult ar2 = f.BeginInvoke(2, null, null);
//...
我想我所倡导的甚至不是自己实施APM,而只是向那些打电话给你的方法的人推荐他们使用内置于代表中的APM。
答案 1 :(得分:0)
恕我直言,我认为您的异步方法不会添加任何值,所以只需让客户端决定它是否会异步调用您的方法。
答案 2 :(得分:0)
我认为这是一个非常有效的练习,如果没有别的。我也正在研究一个异步的'委托'处理程序。您可以增加灵活性,并且您将学习很多关于异步模型的知识。
我知道这个SO question包含一些Linq练习。但是,它可能会让您了解如何使用表达式树来使其更加健壮。我还没有深入研究这个主题,并为您提供更具体的信息。
以下是发布异步方法的旧代码示例。这是学习反思和一些有趣实现的过时练习。把它拿走它的价值,但它可以帮助你提出一些想法:
public delegate void delVoidMethod(params object[] args);
/// <summary>
/// Publishes an asynchronous method to the delegate collection.
/// </summary>
/// <param name="methodOwner">Target object owning the delegated method.</param>
/// <param name="method">The delegated method.</param>
/// <param name="callback">The method designated as a callback delegate.</param>
/// <param name="ptr">The delegated method's runtime handle.</param>
/// <returns>True if publishing was successful.</returns>
public bool PublishAsyncMethod(object target , MethodInfo method ,
MethodInfo callback , out IntPtr ptr)
{
try
{
ptr = method.MethodHandle.Value;
delVoidMethod dMethod = (delVoidMethod)Delegate.CreateDelegate
(typeof(delVoidMethod) , target , method);
AsyncCallback callBack = (AsyncCallback)Delegate.CreateDelegate
(typeof(AsyncCallback) , target , callback);
handlers[ptr] = new DelegateStruct(dMethod , callBack);
Logger.WriteLine("Delegate : {0}.{1} -> {2}.{3} published." ,
method.DeclaringType.Name , method.Name ,
callback.DeclaringType.Name , callback.Name);
return true;
}
catch (ArgumentException ArgEx)
{
Logger.Write(DH_ERROR , ERR_MSG ,
ArgEx.Source , ArgEx.InnerException , ArgEx.Message);
}
catch (MissingMethodException BadMethEx)
{
Logger.Write(DH_ERROR , ERR_MSG ,
BadMethEx.Source , BadMethEx.InnerException , BadMethEx.Message);
}
catch (MethodAccessException MethAccEx)
{
Logger.Write(DH_ERROR , ERR_MSG ,
MethAccEx.Source , MethAccEx.InnerException , MethAccEx.Message);
}
ptr = IntPtr.Zero;
return false;
}
答案 3 :(得分:0)
它绝对没有错,但似乎有点无意义。
您实际上是在实现Facade pattern,但不会使界面变得更简单。可能更好(取决于您的具体情况)添加您自己的类以简化使用AsyncCallback和IAsyncResult,以使调用更准确地反映您的类中使用的属性。
答案 4 :(得分:0)
我个人更喜欢使用事件在异步进程结束时通知,如果该类打算由另一个库使用,则使用AsyncOperation类和SendOrPostCallback委托来确保在调用者线程上引发事件而不会中断用户界面。 但是,如果要在同一个程序集中执行异步操作,我宁愿使用调用代码来定义如何进行异步调用。