使用out参数实现调用委托

时间:2018-04-23 08:39:34

标签: c# delegates decorator out

我尝试实现一个装饰器模式来处理数据库事务中的错误。我对标准Func和Actions没有任何问题,但是我对使用 out 参数的函数有困难。

这里有许多相同问题的主题,我想出来实现我自己的委托:

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

1)但我还没有找到如何基于此委托实现方法:

    private void SafetyExecuteMethod(Action action)
    {
        try
        {
            action();
        }
        catch (Exception ex)
        {
            // Some handling
        }
    }

    private T SafetyExecuteFunction<T>(Func<T> func)
    {
        T result = default(T);
        SafetyExecuteMethod(() => result = func.Invoke());
        return result;
    }

    private SafetyExecuteFunctionWithOut // ??
    {
        // ??
    }

2)如何调用此方法:

    public bool UserExists(string name)
    {
        return SafetyExecuteFunction(() => _innerSession.UserExists(name));
    }

    public void CreateUser(string name, string password)
    {
        SafetyExecuteMethod(() => _innerSession.CreateUser(name, password));
    }

    public bool CanUpdateUser(string userName, out string errorMessage)
    {
        // ??
        // _innerSession.CanUpdateUser(userName, out errorMessage);
    }

1 个答案:

答案 0 :(得分:0)

使用与SafetyExecuteFunction<T>(Func<T> func)示例中相同的方案。

您必须注意的一件事是您需要为out参数使用临时局部变量。

private TResult SafetyExecuteFunctionWithOut<T1, T2, TResult>(FuncWithOut<T1, T2, TResult> func, T1 arg1, out T2 arg2)
{
    TResult result = default(TResult);
    T2 arg2Result = default(T2); // Need to use a temporary local variable here 

    SafetyExecuteMethod(() => result = func(arg1, out arg2Result));

    arg2 = arg2Result; // And then assign it to the actual parameter after calling the delegate.
    return result;
}

调用该函数的工作原理如下:

public bool CanUpdateUser(string userName, out string errorMessage)
{
    bool result = SafetyExecuteFunctionWithOut<string, string, bool>(_innerSession.CanUpdateUser, userName, out errorMessage);
    return result;
}

请注意,您必须将_innerSession.CanUpdateUser作为参数传递给SafetyExecuteFunctionWithOut,而不是使用lambda表达式。

使用天真的尝试:

private TResult SafetyExecuteFunctionWithOut<T1, T2, TResult>(FuncWithOut<T1, T2, TResult> func, T1 arg1, out T2 arg2)
{
    TResult result = default(TResult);

    SafetyExecuteMethod(() => result = func(arg1, out arg2));

    return result;
}

创建错误消息:

  

CS1628无法在匿名内使用ref或out参数'arg2'   方法,lambda表达式或查询表达式

为什么不允许这样做explained in this answer