异步调用带有输出参数的方法

时间:2013-04-29 10:00:33

标签: c# task-parallel-library output-parameter

是否可以使用TPL Task<TResult>以异步方式调用具有以下签名的线程安全方法并检索布尔返回值和输出参数?

public bool TryGet(T1 criteria,
                   out T2 output)

显然由于输出参数,我不能使用lambda表达式。另外,我无法通过定义下面的自定义委托并将其传递给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 个答案:

答案 0 :(得分:4)

这也是我也在努力解决的问题。

我想出了一个类似的解决方案,除了使用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;
    }
}

答案 1 :(得分:1)

我认为你的方法几乎是你能做的最好的方法。如果您经常这样做,您可以使用帮助方法将out参数的委托转换为Tuple - 返回委托(或类似TryResult - 返回,如Matthew Watson所述回答):

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