封装Action <T>和Func <T>?

Alp*_*pha 11 c# parameters action overloading func

我正在尝试为某种IExecutable接口进行设计.我不会详细介绍,但重点是我有几个需要从基类执行的动作.它们可能采用不同的参数(没什么大不了的),它们可能/可能不会返回值.

到目前为止,这是我的设计:

public abstract class ActionBase
{
    // ... snip ...
}

public abstract class ActionWithResultBase<T>: ActionBase
{
    public abstract T Execute();
}

public abstract class ActionWithoutResultBase: ActionBase
{
    public abstract void Execute();
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我的每个具体动作都需要来自ActionWithResultBase或ActionWithoutResult基础的孩子,但我真的不喜欢这样.如果我可以将Execute的定义移动到ActionBase,考虑到具体类可能会或可能不会返回值,我将实现我的目标.

有人告诉我这可以通过使用Func和Action完成,我完全同意,但是我找不到将其转换为单个类的方法,以便调用者知道操作是否将返回值或不.

简介:我想做的事情如下:

// Action1.Execute() returns something.
var a = new Action1();
var result = a.Execute();

// Action2.Execute() returns nothing.
var b = new Action2();
b.Execute();
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 9

如果你想要一个轻量级的解决方案,那么最简单的选择就是编写两个具体的类.一个将包含类型的属性,另一个包含类型Action的属性Func<T>:

public class ActionWithResult<T> : ActionBase { 
  public Func<T> Action { get; set; } 
}

public class ActionWithoutResult : ActionBase {
  public Action Action { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样构造两种类型:

var a1 = new ActionWithResult<int> { 
  CanExecute = true,
  Action = () => { 
    Console.WriteLine("hello!");
    return 10; 
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您不想使Action属性读/写,那么您可以将操作委托作为参数传递给构造函数,并使属性只读.

C#需要两个不同的委托来表示函数和动作这一事实非常烦人.人们使用的一种解决方法是定义一个Unit表示"无返回值" 的类型,并使用它代替void.然后你的类型将是公正的Func<T>,你可以使用Func<Unit>而不是Action.该Unit型看起来是这样的:

public class Unit {
  public static Unit Value { get { return null; } }
}
Run Code Online (Sandbox Code Playgroud)

要创建一个Func<Unit>值,你会写:

Func<Unit> f = () => { /* ... */ return Unit.Value; }
Run Code Online (Sandbox Code Playgroud)