如果C#函数的用户应该始终创建新的委托实例而不是重用

时间:2017-04-14 05:28:22

标签: c# lambda delegates

我有类似于以下的API,它接受委托报告操作的进度。同时返回任务以便取消它。

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

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();
    }

}

1 个答案:

答案 0 :(得分:0)

  

所以我有两个问题

实际上,我看到三个。这是你的第一个(缺少问号不会让它成为问题:)):

  

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

您希望用户如何确定?使用您发布的代码,根本不可能。您可以通过多种方式解决此问题,但如果您正在讨论重新使用相同的委托实例,则必须修改调用的方法:

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

你的其他问题“主要是基于意见的”,所以不太适合Stack Overflow,但是因为我正在写作,所以这是我的两分钱:

  

•为获取委托(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())。被呼叫者可以对可能存在的呼叫者类型保持不可知。

是的,您最终必须创建其他委托实例。但那又怎么样?你在这里经营了很长时间。你不会在一秒钟内创建它们甚至十几个,更不用说在性能问题开始成为一个问题之前它需要的成千上万,更别说真的是解决。