2015-07-01 2 views
2

У меня возникают некоторые проблемы, пытаясь понять, как именно Func работает на C#, несмотря на то, что прочитал несколько хороших блог-постов об этом.Использование Func с задачей в C#

У меня есть следующий сценарий: Я строю небольшую биллинговую систему, которая использует очередь Azure Service Bus для обработки счетов. Там это два процесса, которые могут быть инициализированы пользователем:

  1. Создайте Daybook для проверки того, что операции правильно перед
  2. создания фактического счета-фактуры для клиента

Для этого, я имею сделал общий метод, который инициализирует задачу биллинга (содержащую 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) возвращает ничтожным. Возврат 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, это определенно более просто, чем мой подход :-) Мне действительно нужно 'if-else', так как в методах ServiceBus существует другая логика. –

0

Я вижу две отдельные проблемы: 1. Я боюсь, что Task.Factory.StartNew(() => processMethod) не будет делать то, что вы ожидаете от этого. Он не будет исполнять processMethod. 2. StartQueueProcess определен для принятия функции Func <> с тремя параметрами. Он ничего не говорит о самих параметрах. Это ваша обязанность поставлять эту лямбду с некоторыми параметрами.

Почему вы делаете предположение, что вам нужно использовать 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

Привет, Алексей, спасибо за ваш ответ! :-) Оцените! Я предполагаю, что я пропустил параметры, я думал, что параметры были переданы автоматически (каким-то образом), включив их в вызывающий метод (см. Мой оригинальный почтовый индекс). Я пошел с кодом, который написал Юваль, который выполняет эту работу так, как должен. Использование «Func» для этого было просто из чистого любопытства и попытки узнать что-то новое ;-) –

Смежные вопросы