Включить тип со словарем в Func и async / await

#c# #dictionary #lambda #async-await

#c# #словарь #лямбда #async-ожидание

Вопрос:

Я пытаюсь написать этот фрагмент кода, который не компилируется (материал удален / упрощен):

 private async Task<PatientChartData> GetDomainListingSummaryMeta<T>(string phn) 
    where T : PatientChartBase, new()
{
    var getListingSummaryTypeSwitch = new Dictionary<Type, Func<????>> {
        { typeof(Documents), async () => await this.GetDocuments(phn) },
        { typeof(Encounters), async () => await this.GetEncounters(phn) },
        { typeof(Labs), async () => await this.GetLabs(phn) },
    };
    Task t = new Task(async () =>
    {
        // this is what code would look like without a switch, e.g.
        // await this.GetDocuments(phn);

        // but with a type switch, I want to do something like this:
        await getListingSummaryTypeSwitch(typeof(T))();
    });
    t.Start(); // notice, we are not waiting for this task to complete
}
  

GetDocuments возвращает задачу, GetEncounters возвращает задачу и т. Д. Однако в моем текущем дизайне меня на самом деле не волнует ответ, поскольку я вызываю их в фоновом потоке, Который будет иметь побочные эффекты (например, помещая их в базу данных / кэш и т. Д.) Пожалуйста, не обращайте внимания на проблемы с дизайном, поскольку это фоновые потоки.

Мой вопрос действительно касается синтаксиса о том, как я заставляю это работать.

Комментарии:

1. он не компилируется… вы указали это в своем вопросе, но не говорите нам, в чем ошибка….

2. Рассматривали ли вы возможность использования полиморфизма для решения этой проблемы? Подумайте, если все ваши типы являются производными от общего типа, все они могут по-разному реализовывать абстрактный метод базового класса или общего интерфейса. Тогда вы могли бы просто вызвать этот метод и добиться поведения, зависящего от типа. Ваш словарь устареет.

3. пожалуйста, посмотрите??? в Func<> Плюс, я даже не уверен, будет ли это работать правильно и / или ожидаемо, даже если оно скомпилируется. Должен ли я использовать Action вместо Func? правильно ли используется использование async / await ?

4. Зачем вы вообще создаете здесь универсальный метод, когда вы знаете, что будет ограниченный набор типов, с которыми вы можете юридически обращаться? Почему бы просто не создать N перегрузок с соответствующими именами, имея соответствующий код? Вы должны стремиться к «открытости», способности программиста (которым можете быть вы) определять, какими будут допустимые типы и методы. Используя общий метод T , вы, по сути, говорите: «Этот метод может принимать любой тип», а затем после этого все это «не-а, обманул тебя».

5. @lassevkarlsen прав. Если ваш общий код правильно обрабатывает только определенные типы, он не должен быть общим.

Ответ №1:

вы хотите использовать тип в качестве индексатора, а не в качестве аргумента?

         await getListingSummaryTypeSwitch[typeof(T)]();
  

Что касается вашего Func<???> : он должен возвращать ожидаемый, иначе вы не сможете использовать await перед своим коммутатором. Обычно вы бы использовали Func<Task> или что-то общее Func<Task<resulttype>> .

Я не буду обсуждать другие недостатки (например, перенос в другую задачу), которые обсуждаются в разделе комментариев к вашему вопросу, потому что вы сказали, что упростили его.

Ответ №2:

Вот что я в итоге сделал. Как многие отмечали — этот код, хотя он и работает, ужасный дизайн. Это было просто что-то быстрое и грязное, что мы создавали прототипы. Это началось с того, что мой босс попросил 1 домен … затем он попросил еще 2 и т.д. Я не хотел реорганизовывать все свои классы, чтобы использовать соответствующие интерфейсы / полиморфизм, поскольку мы постоянно что-то меняли во внутренних реализациях, и (б) я решил, что это «общее» использование будет для меня быстрым способом предотвратить дублирование кода. Надеюсь, это поможет всем, кому это может понадобиться.

             var actionSwitch = new Dictionary<Type, Action> {
                { typeof(Documents), async () => await _patientProcessorService.GetDocuments(phn) },
                { typeof(Encounters), async () => await _patientProcessorService.GetEncounters(phn) },
                { typeof(Labs), async () => await _patientProcessorService.GetLabs(phn) },
            };

            Task t = new Task(async () =>
            {
                actionSwitch[typeof(T)]();

            });
            t.Start(); 
  

Комментарии:

1. Для каких-либо из этих действий нет причин, для async await методов нет причин. Нет причин создавать новую задачу для вызова действия, а если бы и были, это не должно быть async лямбда, и вы не должны использовать Task конструктор для запуска задач.