制作一个函数,可以采取 属性 of Action<T> 或 Action

Make a function that can take property of Action<T> or Action

我有以下两个功能:

private void CallVoidFunction(Action action, object property = null)
{
    //Lots of code duplicated here 
    action.Invoke();
    //and here between teh 2 methods
}

private void CallVoidFunction<T>(Action<T> action, object property = null)
{
    //Lots of code duplicated here 
    action.Invoke((T)property);
    //and here between teh 2 methods
}

有没有办法将这些组合成一个函数,该函数采用 Action 的通用 属性 ? 否则我会有很多重复的代码。我知道可以把重复的代码组合成函数调用,但是可以吗?

ActionAction<T> 似乎不是从同一个基础派生的,所以我认为它无法完成?

我正在按照它们派生的接口思路进行思考,但我看不到任何共同点?

下面是我能想到的最好的方法,但我希望有更简单的方法。

public class ActionContainer<T>
    {
        public ActionContainer(Action<T> actionT, Action action, object property)
        {
            _actionT = actionT;
            _action = action;
            _property = property;
        }

        public void Invoke()
        {
            if (_property != null)
                _actionT.Invoke((T)_property);
            else
                _action.Invoke();
        }

        private object _property { get; set; }
        private Action<T> _actionT { get; set; }
        private Action _action { get; set; }
    }

你应该能够像这样从第二个调用第一个,这样你就可以避免代码重复:

private void CallVoidFunction<T>(Action<T> action, object property = null)
{
    CallVoidFunction(() => action.Invoke((T)property), property);
}

Action<T> 表示接受 1 个 T 类型参数的 void 函数,而 Action 表示没有参数的 void 函数。

因此您需要重载,因为没有函数与两个签名匹配。

但是,您可以使用闭包来避免重复:

private void CallVoidFunction<T>(Action<T> action, T property = default)
    => CallVoidFunction(() => action(property));

private void CallVoidFunction(Action action)
{
    //...
    action();
    //...
}

这将接受 T 的函数包装在一个没有参数的函数中。

您还应该将 property 声明为 T,而不是反对强制执行 type-safety。


如果 property 仅用作 action 的参数,另一种方法是完全删除通用版本并让调用者制定闭包。

如果 CallVoidFunction 确实需要以某种方式使用 property,那么重载是您唯一的选择:

private void CallVoidFunction<T>(Action<T> action, T property = default)
{
    // Do something with property..
    CallVoidFunction(() => action(property));
}

这与 Johnathan Barclay 的 相似,但相反。您首先要完全实现通用版本。然后 non-generic 版本可以从通用版本派生,传递一个虚拟 (object)null 参数。

private void CallVoidFunction<T>(Action<T> action, T property = default)
{
    //...
    action(property);
    //...
}

private void CallVoidFunction(Action action)
    => CallVoidFunction<object>(_ => action(), null);

优点是 property 在完整实现中可用,如果您出于某种原因(如日志记录)需要它。