2017-04-14 46 views
-1

我有类似于以下的API,这需要委托来报告操作的进度。也返回任务,以便它可以被取消。C#函数的用户应该总是创建委托的新实例而不是重用

如果此函数的用户对多个函数调用使用相同的委托实例,那么用户 将如何确定哪个进度用于哪个函数调用。

class Program 
{ 
    public static Task LongOperationAsync(List<String> names, Action<String> progress) 
    { 
     return Task.Factory.StartNew(() => 
     { 
      foreach (var item in names) 
      { 
       // do some long operation 
       progress(item.ToUpper()); 
      } 
     }); 

    } 

    static void Main(string[] args) 
    { 
     var friends = new List<String>() {"joey","ross","chandler","monica","phoebe","rachel" }; 
     var seinfelds = new List<String>() { "Jerry", "kramer", "george", "elaine" }; 

     Action<String> resultProcessor = (result) => 
     { 
      // process the result. let's say update the UI as and when results arrive 
      Console.WriteLine(result); 
     }; 
     var task1 = LongOperationAsync(friends, resultProcessor); 
     var task2 = LongOperationAsync(seinfelds, resultProcessor); 
     Task.WaitAll(task1, task2); 
     Console.ReadLine(); 
    } 

} 
+0

您可以将进度重新定义为“Action progress',然后将进度所属的对象包含在对动作的调用中。 – john

+0

旁注:你应该使用Task.Run而不是Factory.Startnew:https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html – GWigWam

回答

0

所以我有2个问题

其实,我看到有三。这是你的第一个问题(缺少问号不会妨碍它成为问题:)):

用户如何确定哪个进度是哪个函数调用的。

你怎么想的用户来确定?随着你发布的代码,它根本不可能。有很多种的,你可以解决这个问题的方法,但如果你是在谈论重新使用相同的委托实例,你就必须修改调用方法:

public static Task LongOperationAsync(List<String> names, Action<String> progress, string id) 
{ 
    return Task.Factory.StartNew(() => 
    { 
     foreach (var item in names) 
     { 
      // do some long operation 
      progress($"{id}: {item.ToUpper()}"); 
     } 
    }); 
} 

static void Main(string[] args) 
{ 
    var friends = new List<String>() {"joey","ross","chandler","monica","phoebe","rachel" }; 
    var scienfelds = new List<String>() { "Jerry", "kramer", "george", "elaine" }; 

    Action<String> resultProcessor = (result) => 
    { 
     // process the result. let's say update the UI as and when results arrive 
     Console.WriteLine(result); 
    }; 
    var task1 = LongOperationAsync(friends, resultProcessor, "task1"); 
    var task2 = LongOperationAsync(scienfelds, resultProcessor, "task2"); 
    Task.WaitAll(task1, task2); 
    Console.ReadLine(); 
} 

或相关的选择,如果你想回调本身要能知道哪个任务的进展情况是:

public static Task LongOperationAsync(List<String> names, Action<String, String> progress, string id) 
{ 
    return Task.Factory.StartNew(() => 
    { 
     foreach (var item in names) 
     { 
      // do some long operation 
      progress(item.ToUpper(), id); 
     } 
    }); 
} 

你的其他问题是“主要意见为基础”,因此不太适合堆栈溢出,但因为我在写反正,这里是我的两分钱:

•将用户提供的信息用于需要委托的功能(Action或Func)总是良好的做法吗?

始终?不是。这取决于上下文。

•是否推荐在多个函数调用中重用委托实例?

这也取决于上下文。如果您可以方便地执行此操作,或者如果您处于其他情况下需要创建大量委托实例的场景,那么您应该重新使用一个实例。

但只要没有严重的性能问题(通常不会有),你应该写在最有意义,而不是担心创建对象的方式的代码。

例如,替代你的代码,其中的代表是重用,会是这个样子:

static void Main(string[] args) 
{ 
    var friends = new List<String>() {"joey","ross","chandler","monica","phoebe","rachel" }; 
    var scienfelds = new List<String>() { "Jerry", "kramer", "george", "elaine" }; 

    Action<String, String> resultProcessor = (result, id) => 
    { 
     // process the result. let's say update the UI as and when results arrive 
     Console.WriteLine($"{id}: {result}"); 
    }; 
    var task1 = LongOperationAsync(friends, r => resultProcessor(r, "task1")); 
    var task2 = LongOperationAsync(scienfelds, r => resultProcessor(r, "task2")); 
    Task.WaitAll(task1, task2); 
    Console.ReadLine(); 
} 

这样,回调定制客户端的需求代码,而不需要更改被调用者(即不需要更改为LongOperationAsync())。被叫方可以保持对可能有哪些类型的呼叫者不知情。

是的,你不得不创建额外的委托实例。但那又如何?你在这里做了很长时间的手术。你甚至不会在一秒钟内创建十几个,在性能问题甚至开始成为问题之前,不用介意它需要的数以万计的成本,没关系需要解决。

相关问题