Асинхронный вызов метода с выходным параметром
Можно ли использовать TPL Task<TResult>
асинхронно вызвать потокобезопасный метод со следующей сигнатурой и получить логическое возвращаемое значение и выходной параметр?
public bool TryGet(T1 criteria,
out T2 output)
Очевидно, я не могу использовать лямбда-выражение из-за выходного параметра. Кроме того, я не могу решить проблему, определив пользовательский делегат, такой как ниже, и передав его Task<TResult>
конструктор, поскольку мне нужно передать критерии как строго типизированный параметр, который конструктор не поддерживает.
public delegate TResult Func<T1, T2, TResult>(T1 arg1,
out T2 arg2);
Является ли лучшим вариантом написать обертку, такую как ниже, и вместо этого вызывать ее асинхронно?
public Tuple<bool, T2> TryGetWrapper(T1 criteria)
{
T2 output;
bool result = obj.TryGet(criteria,
out output);
return new Tuple<bool, T2>(result,
output);
}
Просто кажется немного неэластичным и немного нюхает об этом.
2 ответа
Это то, с чем я тоже боролся.
Я придумал похожее решение, за исключением того, что вместо того, чтобы использовать Tuple, я написал простой класс-обертку, чтобы сделать вещи немного более читабельными.
Мне также было бы интересно найти лучшее решение, но то, что вы предлагаете, кажется таким же хорошим, как и все, что я придумал.
Вот как выглядит мой класс-оболочка и его использование. Это не ответ на ваш вопрос; просто предложение (возможно) сделать ваше решение немного более читабельным.
(Хотя я признаю, что Task<TryResult<DateTime>>
Само объявление не может считаться таким читаемым!)
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;
}
}
Я думаю, что ваш подход - это лучшее, что вы можете сделать. Если вы делаете это часто, вы можете использовать вспомогательный метод, который преобразует делегата с out
параметр к Tuple
Возврат делегата (или что-то вроде TryResult
возвращаясь, как в ответе Мэтью Уотсона):
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);
};
}