Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#链接操作_C#_Action_Chain - Fatal编程技术网

C#链接操作

C#链接操作,c#,action,chain,C#,Action,Chain,我想实现类似于任务链接方式的目标: Task.Factory.StartNew(() => { }) .ContinueWith((t) => { }) .ContinueWith((t) => { }) ... .ContinueWith((t) => { }); 但是,我不需要异步运行这些操作。我希望能够链接操作(执行第一个、第二个、第三个等),最重要的是,我希望添加一个 .Catch((a) => { } 当链中的任何操作

我想实现类似于任务链接方式的目标:

Task.Factory.StartNew(() => { })
    .ContinueWith((t) => { })
    .ContinueWith((t) => { })
    ...
    .ContinueWith((t) => { });
但是,我不需要异步运行这些操作。我希望能够链接操作(执行第一个、第二个、第三个等),最重要的是,我希望添加一个

.Catch((a) => { } 
当链中的任何操作引发错误时要执行的操作

最后,我希望它看起来像这样:

Actions.Factory.Execute(() => {
    Foo foo = new Foo();
    Bar bar = new Bar();
    if (foo != bar) 
        throw new Exception('Incompatible Types!);
}).Catch((ex) => {
    MyFancyLogger.LogError("Something strange happened: " + ex.Error.ToString();
});
我曾尝试实现一个工厂类,该类在继承自Action类的派生类上工作,但不幸的是,“Action”类是密封的,因此无法工作

编辑:

我这样做的主要原因是,我希望记录每个包装操作的统计信息,并根据严重性以不同的方式处理错误。目前,我正在执行一个带有以下签名的操作:

public static void ExecuteAction(this Action action, 
    string name = "", 
    int severity = 0, 
    bool benchmark = false, 
    bool logToDb = false, 
    [CallerMemberName]string source = "", 
    [CallerFilePath]string callerLocation = "", 
    [CallerLineNumber]int lineNo = 0) {
    // Wrap the whole method in a try catch
    try {
        // Record some statistics
        action.Invoke();
        // Record some statistics
    } catch (Exception ex) {
        if (severity > 3) {
             // Log to DB
        } else Logger.WriteError(ex);
        throw ex;
    }
}
这样称呼:

(() => {
    //this is the body
}).ExecuteAction("Description of the method", 3, true, false);
在我看来,这本书很好用,而且读起来也很容易。现在我只想添加一个.Catch:

(() => {
    //this is the body
})
.ExecuteAction("Description of the method", 3, true, false)
.Catch((e) => {
    MessageBox.Show("This shouldn't have happened...");
});

我认为这个方法可以一个接一个地执行所有任务,并用
try包装。。。如果我正确理解您的要求,catch
就足够了

public async Task Execute(IEnumerable<Func<Task>> actions, Action catchAction)
{
    try
    {
        foreach (var action in actions)
        {
            await action();
        }
    }
    catch (Exception ex)
    {
        catchAction()
    }
}
回应关于可读性的评论

当然,将所有操作内联将违反任何以集合为参数的api的可读性

通常您有一些实例或静态方法的方法,在本例中,调用如下

var actions = new Action[]
{
    StaticClass.Action1,
    SomeInstance.Action2,
    AnotherStaticClass.Action3
}

await Execute(actions, Logger.Log);
您可以使用的另一种方法是“构建器模式”

公共类执行器
{
私人名单(行动);;
私人行动;
公共遗嘱执行人()
{
_actions=新列表();
_catchAction=异常=>{};
}
公共执行人(职能行动)
{
_动作。添加(动作);
归还这个;
}
公共执行人CatchBy(行动catchAction)
{
_catchAction=catchAction;
}
公共异步任务运行()
{
var tasks=_actions.Select(action=>action());
尝试
{
等待任务。何时(任务);
}
捕获(例外情况除外)
{
_捕集行动()
}            
}
}
然后使用它

Func<Task> doSomeDynamicStaff = () => 
{
    // Do something
}
var executor = new Executor().With(StaticClass.DoAction1)
                             .With(StaticClass.DoAction2)
                             .With(StaticClass.DoAction3)
                             .With(doSomeDynamicStaff)
                             .CatchBy(Logger.Log);

await executor.Run();
Func-doSomeDynamicStaff=()=>
{
//做点什么
}
var executor=new executor().With(StaticClass.DoAction1)
.With(StaticClass.DoAction2)
.With(StaticClass.DoAction3)
.带(doSomeDynamicStaff)
.CatchBy(Logger.Log);
等待执行器。Run();

尽管如此,您将如何称呼它,它仍然应该很容易阅读并弄清楚发生了什么。。我已将您的签名更改为以下内容以尝试改进:
public void Execute(Action catchAction,params Action[]actions){…}
但即使这样也感觉不可读:
Execute(()=>{//这是Catch},()=>{//这是链中的第一个操作},()=>{//这是链中的第二个操作});
@johanapeling,检查更新的答案。我有点奇怪,为什么要将所有操作都称为“内联”?相反,您可以将函数作为变量引入,这将更具可读性,或者更好地将它们分组到类或静态类中。我已使用此方法修复了我的解决方案。感谢您的帮助,这是我所需要的100%!
public class Executor
{
    private List<Func<Task>> _actions;
    private Action<Exception> _catchAction;
    public Executor()
    {
        _actions = new List<Func<Task>>();
        _catchAction = exception => { };
    }

    public Executor With(Func<Task> action)
    {
        _actions.Add(action);
        return this;
    }

    public Executor CatchBy(Action<Exception> catchAction)
    {
        _catchAction = catchAction;
    }

    public async Task Run()
    {
        var tasks = _actions.Select(action => action());
        try
        {
            await Task.WhenAll(tasks);
        }
        catch (Exception ex)
        {
            _catchAction()
        }            
    }
}
Func<Task> doSomeDynamicStaff = () => 
{
    // Do something
}
var executor = new Executor().With(StaticClass.DoAction1)
                             .With(StaticClass.DoAction2)
                             .With(StaticClass.DoAction3)
                             .With(doSomeDynamicStaff)
                             .CatchBy(Logger.Log);

await executor.Run();