使用 out 参数实现调用委托

Implement calling delegate with out parameters

我尝试实现一个装饰器模式来处理数据库事务中的错误。我对标准 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);
    }

只需使用与 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 Cannot use ref or out parameter 'arg2' inside an anonymous method, lambda expression, or query expression

不允许您这样做的原因是 explained in this answer