Asynchronous method call with output parameter

Is it possible to use TPL Task<TResult> to asynchronously call a thread-safe method with the following signature and get a logical return value and output parameter?

 public bool TryGet(T1 criteria, out T2 output) 

Obviously, I cannot use a lambda expression because of the output parameter. In addition, I cannot solve the problem by defining a user delegate, such as below, and passing it to the Task<TResult> constructor, since I need to pass the criteria as a strongly typed parameter that the constructor does not support.

 public delegate TResult Func<T1, T2, TResult>(T1 arg1, out T2 arg2); 

Is it best to write a shell like below and invoke asynchronously instead?

 public Tuple<bool, T2> TryGetWrapper(T1 criteria) { T2 output; bool result = obj.TryGet(criteria, out output); return new Tuple<bool, T2>(result, output); } 

It just seems a little inelegant and a little thoughtful.

+4
source share
2 answers

This is what I also fought with.

I came up with a similar solution, but instead of using Tuple, I wrote a simple wrapper class to make things more readable.

I would also be interested to see any best solution, but what you offer seems as good as everything that I came up with.

This is what my wrapper class and its use look like. This is not an answer to your question; just a suggestion (possibly) to make your decision more understandable.

(Although I admit that the Task<TryResult<DateTime>> declaration itself cannot be considered as readable!)

 using System; using System.Threading.Tasks; namespace ConsoleApplication1 { internal class Program { static void Main() { string dateString = "Invalid Date"; var tryParseDateTask = new Task<TryResult<DateTime>>(() => { DateTime result; if (DateTime.TryParse(dateString, out result)) return TryResult<DateTime>.Success(result); else return TryResult<DateTime>.Failure(); }); tryParseDateTask.Start(); if (tryParseDateTask.Result.IsSuccessful) Console.WriteLine(dateString + " was parsed OK."); else Console.WriteLine(dateString + " was parsed as " + tryParseDateTask.Result.Value); } } public class TryResult<T> { public static TryResult<T> Success(T value) { return new TryResult<T>(value, true); } public static TryResult<T> Failure() { return new TryResult<T>(default(T), false); } TryResult(T value, bool isSuccessful) { this.value = value; this.isSuccessful = isSuccessful; } public T Value { get { return value; } } public bool IsSuccessful { get { return isSuccessful; } } readonly T value; readonly bool isSuccessful; } } 
+4
source

I think your approach is pretty much the best you can do. If you do this often, you can use a helper method that converts the delegate with the out parameter to a Tuple curing delegate (or something like TryResult return, as in Matthew Watson's answer):

 public delegate TResult OutFunc<TIn, TOut, TResult>(TIn input, out TOut output); public static Func<TIn, Tuple<TResult, TOut>> OutToTuple<TIn, TOut, TResult>( OutFunc<TIn, TOut, TResult> outFunc) { return input => { TOut output; TResult result = outFunc(input, out output); return Tuple.Create(result, output); }; } 
+1
source

All Articles