制作一个可以采用Action <T>或Action

问题描述

我具有以下2个功能

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

解决方法

Action<T>表示一个空函数,它接受1个类型为T的参数,而Action表示一个空函数,不带参数。

由于没有函数同时匹配两个签名,因此您将需要重载。

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

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

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

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

您还应该将property声明为T,而不是强制执行类型安全性的对象。


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

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

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

这类似于Johnathan Barclay的answer,但相反。您首先要完全实现通用版本。然后可以从非常规版本派生非常规版本,并传递一个伪(object)null参数。

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

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

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

,

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

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