Completing an Asynchronous Invocation of a Delegate with Partial Type Information

When writing implementations of the asynchronous use method using the BeginInvoke / EndInvoke template, the code may look something like this (and so you guess that it is an asynchronous shell around the cache):

IAsyncResult BeginPut(string key, object value) { Action<string, object> put = this.cache.Put; return put.BeginInvoke(key, value, null, null); } void EndPut(IAsyncResult asyncResult) { var put = (Action<string, object>)((AsyncResult)asyncResult).AsyncDelegate; put.EndInvoke(asyncResult); } 

This works fine because he knows what a delegate type is, so it can be distinguished. However, it starts to get confused when you have two Put methods, because although the method returns void, you seem to need to give it to a strongly typed delegate to end the call, for example.

 IAsyncResult BeginPut(string key, object value) { Action<string, object> put = this.cache.Put; return put.BeginInvoke(key, value, null, null); } IAsyncResult BeginPut(string region, string key, object value) { Action<string, string, object> put = this.cache.Put; return put.BeginInvoke(region, key, value, null, null); } void EndPut(IAsyncResult asyncResult) { var put = ((AsyncResult)asyncResult).AsyncDelegate; var put1 = put as Action<string, object>; if (put1 != null) { put1.EndInvoke(asyncResult); return; } var put2 = put as Action<string, string, object>; if (put2 != null) { put2.EndInvoke(asyncResult); return; } throw new ArgumentException("Invalid async result", "asyncResult"); } 

I hope there is a cleaner way to do this, because the delegate's only concern is the type of return (in this case void), and not the arguments that were provided to him. But I racked my brains and asked others in the office, and no one can come up with an answer.

I know that one solution is to write a custom IAsyncResult , but such a difficult task with potential IAsyncResult problems around things like the lazy WaitHandle creation, that I would rather have this slightly hacked code than go down this route.

Any ideas on how to end a call without a cascading set of is checks?

+4
source share
3 answers

I was mistaken, there is a cleaner way.

You create Action( IAsyncResult ) delegates Action( IAsyncResult ) for a specific EndInvoke() method in the same context where you already know the specific delegate type, passing it as AsyncState. I pass EndPut() as a callback for convenience.

 IAsyncResult BeginPut( string key, object value ) { Action<string, object> put = this.Put; return put.BeginInvoke( key, value, EndPut, new Action<IAsyncResult>( put.EndInvoke ) ); } IAsyncResult BeginPut( string region, string key, object value ) { Action<string, string, object> put = this.Put; return put.BeginInvoke( region, key, value, EndPut, new Action<IAsyncResult>( put.EndInvoke ) ); } 

And then you are done.

 void EndPut( IAsyncResult asyncResult ) { var del = asyncResult.AsyncState as Action<IAsyncResult>; del( asyncResult ); } 
+4
source

Why not avoid the problem by simply returning to a more general overload:

 IAsyncResult BeginPut(string key, object value) { return this.BeginPut(null, key, value); } IAsyncResult BeginPut(string region, string key, object value) { Action<string, string, object> put = this.Put; return put.BeginInvoke(region, key, value, null, null); } void EndPut(IAsyncResult asyncResult) { var put = (Action<string, string, object>)((AsyncResult)asyncResult).AsyncDelegate; put.EndInvoke(asyncResult); } 
0
source

Edit: See my other answer. It may be cleaner.

I don’t think there is a way to make it cleaner. You essentially made this inevitable by using the same EndPut method to complete more than one type of asynchronous call. You could just follow the normal pattern by passing EndPut and put delegate as the last two parameters in BeginInvoke() (callback and asyncstate), and you still have to check what type of delegate is in order call EndInvoke() .

Passing them to Delegate does not help at all.

I like the idea of ​​Mark Brackett. I think it comes down to the following options:

  • Join them completely if one of them overloads the challenge of the other. One delegate, one callback.
  • Separate them completely by getting two callbacks to call EndInvoke() .

In addition, you need to make the code a little cleaner and use a switch or a search dictionary using asyncResult.AsyncState.GetType() , passing the put delegate as this state object.

0
source

Source: https://habr.com/ru/post/1277631/


All Articles