2015-07-01 40 views
2

我在尝试了解Func在C#中的工作原理时遇到了一些问题,尽管已阅读了少量好博客文章。在C#中使用Func处理任务#

我有以下情形: 我正在构建一个使用Azure服务总线队列处理帐单的小型帐单系统。还有,可以由用户初始化两个过程:

  1. 用于检查之前,为客户创造

的实际发票对于这个

  • 的交易是正确的创建日记帐,我已经提出了一种初始化计费任务(包含N个帐单)的一般方法,该方法需要一个bool参数来确定是否需要创建一个日记帐或实际帐单。在此方法中,我运行以下检查:

    if (isDayBookProcessing) 
    { 
        // Daybook processing code here 
    } 
    else 
    { 
        // Run queue process async 
        StartQueueProcess(queueName, billingTaskId, numOfItemsEnqueued); 
    } 
    

    然后我有一个一般的“StartQueueProcess”的方法,这是在它自己的运行Task像这样:

    private void StartQueueProcess(string queueName, int billingTaskId, int numOfItemsEnqueued) 
    { 
        Task.Factory.StartNew(() => _factory.AzureFactory.ServiceBus.ProcessBillingQueue(queueName, billingTaskId, numOfItemsEnqueued)); 
    } 
    

    正如你可以看到,StartQueueProcess方法运行ProcessBillingQueue方法对我ServiceBus类,这意味着它不能运行ProcessDaybookQueue

    我最初以为是只利用Func<string, int, int, bool>的d使StartQueueProcess方法返回一个布尔(因为Func需要返回的东西),使它看起来像这样:

    if (isDayBookProcessing) 
    { 
        // Daybook processing code here 
        StartQueueProcess(_factory.AzureFactory.ServiceBus.ProcessDaybookQueue(queueName, billingTaskId, numOfItemsEnqueued)); 
    } 
    else 
    { 
        // Run queue process async 
        StartQueueProcess(_factory.AzureFactory.ServiceBus.ProcessBillingQueue(queueName, billingTaskId, numOfItemsEnqueued)); 
    } 
    
    private bool StartQueueProcess(Func<string, int, int, bool> processMethod) 
    { 
        Task.Factory.StartNew(() => processMethod); 
    
        return true; 
    } 
    

    然而,这给出了一个错误,告诉我,Argument type 'void' is not assignable to parameter type 'System.Func<string, int, int bool>'

    _factory.AzureFactory.ServiceBus.ProcessDaybookQueue(queueName, billingTaskId, numOfItemsEnqueued)返回void。使其返回Func<string, int, int, bool>不会导致错误。但为什么呢?我应该不能让它返回我想要的(即无效)?

    任何人都可以对此有所了解吗? :-)

  • +0

    有关这个主题的大文章:http://goo.gl/gWgzPP –

    +0

    非常感谢! :-) –

    回答

    2

    你不需要Func,你需要一个Action。 A Func是您的委托具有返回值的时候。一个Action适合当没有返回值:

    private void StartQueueProcess(Action<string, int, int> processMethod) 
    { 
        Task.Factory.StartNew(() => processMethod); 
    } 
    

    注意,该包装async over sync is an anti-pattern。你最好在调用点而不是使用Task.Run

    if (isDayBookProcessing) 
    { 
        // Daybook processing code here 
        Task.Run(() => _factory.AzureFactory.ServiceBus.ProcessDaybookQueue(
              queueName, 
              billingTaskId, 
              numOfItemsEnqueued)); 
    } 
    else 
    { 
        // Run queue process async 
        Task.Run(() => _factory.AzureFactory.ServiceBus.ProcessBillingQueue(
              queueName, 
              billingTaskId, 
              numOfItemsEnqueued)); 
    } 
    

    虽然我看你是在调用同样的方法,所以我没有看到一个if-else的需要。

    +1

    感谢您的回答Yuval,这绝对比我的方法更简单:-)由于ServiceBus方法中存在不同的逻辑,我确实需要'if-else'。 –

    0

    我看到两个单独的问题: 1.恐怕Task.Factory.StartNew(() => processMethod)不会做你期望的事情。它不会执行processMethod。 2. StartQueueProcess被定义为接受具有三个参数的函数。它没有提到参数本身。这是你的责任提供这个lambda与一些参数。

    你为什么假设你需要在这里使用Func<>?你不需要。您的StartQueueProcess可以这样喜欢:

    private bool StartQueueProcess(
        string param1, 
        int param2, 
        int param3, 
        Action<string, int, int> processMethod) 
    { 
        Task.Factory.StartNew(() => processMethod(param1, param2, param3)); 
    } 
    

    E.g.这个StartNew重载会高兴地接受任何Action参数)。

    此外,在这种特殊情况下,我不认为需要声明一个新的函数。一个简单的通话.StartNew可能会做得很好(这是密切虽然):

    if (isDayBookProcessing) 
    { 
        // Daybook processing code here 
        Task.Factory.StartNew(() => _factory 
         .AzureFactory 
         .ServiceBus 
         .ProcessDaybookQueue(queueName, billingTaskId, numOfItemsEnqueued)); 
    } 
    else 
    { 
        // Run queue process async 
        Task.Factory.StartNew(() => _factory 
         .AzureFactory 
         .ServiceBus 
         .ProcessBillingQueue(queueName, billingTaskId, numOfItemsEnqueued)); 
    } 
    
    +0

    嗨阿列克谢,谢谢你的回答! :-)赞赏!我想我错过的是参数,我认为通过将它们包含在调用方法中(参见我的原始邮政编码),会自动传递参数(以某种方式)。我用代码Yuval写的代码去完成工作,因为它应该这样做。为此,使用'Func'只是出于纯粹的好奇心,试图学习新的东西;-) –