2017-08-31 82 views
3

我要實現類似的任務是如何被鏈接的內容:C#鏈接操作

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類繼承工作,但不幸的是,「操作」類被密封,所以不會工作。

編輯:

我給這主要的原因是我想記錄每個包裹的行爲統計,以及不同的處理根據嚴重程度錯誤。目前,我通過執行具有以下簽名的一個動作做這個:

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..."); 
}); 

回答

1

我認爲它執行的所有任務一個接一個,並通過try ... catch包裹方法就足夠了,如果我理解正確的要求。

public async Task Execute(IEnumerable<Func<Task>> actions, Action catchAction) 
{ 
    try 
    { 
     foreach (var action in actions) 
     { 
      await action(); 
     } 
    } 
    catch (Exception ex) 
    { 
     catchAction() 
    } 
} 

方法的消費上面將負責在正確order.'創建任務的集合

然而接下來的要求似乎有點混亂投標

不過,我不需要這些行動同步運行。我想 能夠鏈操作(執行第一,那麼第二個,然後是第三 等)

如果不需要動作被同步運行,那麼你就可以開始在執行所有這些一次(大約「一次」),並觀察其完成由try .. catch

public async Task Execute(IEnumerable<Func<Task>> actions, Action catchAction) 
{ 
    var tasks = actions.Select(action => action()); 
    try 
    { 
     await Task.WhenAll(tasks); 
    } 
    catch (Exception ex) 
    { 
     catchAction() 
    } 
} 

包裹在關於可讀性

當然的評論的反應,把所有的行動都會內嵌違反任何API的可讀性將Ta kes收藏作爲參數。

通常你有一些實例或靜態方法的方法,在這種情況下調用將看起來像

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

await Execute(actions, Logger.Log); 

另一種方法,你可以用的是「建造者模式」

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(); 
+0

你怎麼稱呼它雖然它應該仍然很容易閱讀和弄清楚發生了什麼..我改變了你的簽名下面的嘗試和改進的是: '公共無效執行(行動catchAction,則params操作[]動作){ ... }' 但即使這樣感覺不可讀: '執行(( )=> {// 這是捕捉 }, ()=> { //這是在鏈中 第一個動作},()=> { //這是該鏈中的第二動作 });' –

+0

@JohanAspeling,檢查更新的答案。我有點奇怪,爲什麼你想要所有的行動「內聯」?相反,你可以引入函數作爲變量,這將更具可讀性,或者甚至可以更好地將它們分組在類或靜態類中 – Fabio

+0

我已經使用這種方法來修復我的解決方案。感謝您的幫助,它是我需要的100%! –