我正在尝试为某种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();
}
到目前为止,我的每个具体动作都需要来自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();
答案 0 :(得分:9)
如果你想要一个轻量级的解决方案,那么最简单的选择就是编写两个具体的类。一个属性包含Action
类型的属性,另一个属性类型为Func<T>
:
public class ActionWithResult<T> : ActionBase {
public Func<T> Action { get; set; }
}
public class ActionWithoutResult : ActionBase {
public Action Action { get; set; }
}
然后你可以构建这两种类型:
var a1 = new ActionWithResult<int> {
CanExecute = true,
Action = () => {
Console.WriteLine("hello!");
return 10;
}
}
如果你不想让Action
属性读/写,那么你可以将动作委托作为参数传递给构造函数,并使属性只读。
C#需要两个不同的委托来表示函数和动作这一事实非常烦人。人们使用的一种解决方法是定义表示“无返回值”的类型Unit
,并使用它代替void
。那么您的类型就是Func<T>
,您可以使用Func<Unit>
代替Action
。 Unit
类型可能如下所示:
public class Unit {
public static Unit Value { get { return null; } }
}
要创建Func<Unit>
值,您需要写:
Func<Unit> f = () => { /* ... */ return Unit.Value; }
答案 1 :(得分:2)
以下接口应该可以解决这个问题 - 它本质上是复制Nullable模式
public interface IActionBase
{
bool HasResult { get; }
void Execute() { }
object Result { get; }
}
public interface IActionBase<T> : IActionBase
{
new T Result { get; }
}
public sealed class ActionWithReturnValue<T> : IActionBase<T>
{
public ActionWithReturnValue(Func<T> action) { _action = action; }
private Func<T> _action;
public bool HasResult { get; private set; }
object IActionBase.Result { get { return this.Result; } }
public T Result { get; private set; }
public void Execute()
{
HasResult = false;
Result = default(T);
try
{
Result = _action();
HasResult = true;
}
catch
{
HasResult = false;
Result = default(T);
}
}
}
public sealed class ActionWithoutReturnValue : IActionBase
{
public bool HasResult { get { return false; } }
object IActionBase.Result { get { return null; } }
public void Execute() { //... }
}
答案 2 :(得分:0)
您知道可以忽略方法的返回值吗?你没有 来使用它。
答案 3 :(得分:0)
简单的事情:
public class ActionExecuter
{
private MulticastDelegate del;
public ActionExecuter(MulticastDelegate del)
{
this.del = del;
}
public object Execute(params object[] p)
{
return del.DynamicInvoke(p);
}
}