Как я могу добавить универсальные функции в список и выполнить их? - PullRequest
0 голосов
/ 04 октября 2018

Я пытаюсь создать слой абстракции для своей очереди, чтобы улучшить интеграционные тесты.Реальная очередь - это RabbitMq через EasyNetQ.

В моей программе я подписываюсь на события, с помощью которых я связываю методы с определенными типами событий - когда событие публикуется, я хочу, чтобы метод выполнялся.Это, конечно, хорошо работает при использовании реальной вещи.

Однако это делает мои тесты зависимыми от сервера RabbitMq, и это заставляет код выполнять асинхронно, что, во-первых, затрудняет определение того, когда тест следует считать завершенным.

Я быне используйте этот вопрос для обсуждения решения абстрагировать RabbitMq в моих тестах.

Чтобы создать заглушку для использования в моих тестах, мне нужно сохранить ссылку на обработчики событий - и мне нужновыполнять обработчики событий, когда впоследствии публикуются события соответствующих типов.

Поэтому я думаю, что мне нужен код, подобный тому, что я написал ниже.Я могу хранить обработчики событий как делегаты, но как их вызвать?Обработчики событий RabbitMq находятся в форме Func, где T - тип события, которое обрабатывает обработчик.

Func<int, Task> handle1 = ...;
Func<string, Task> handle2 = ...;

List<> l = new List<>();
l.Add( handle1);
l.Add( handle2);

foreach(Func f in l)
{
  if (f-parameter is string)
  {
    f("");
  }
  if (f-parameter is int)
  {
    f(1);
  }
}

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Я получил следующее решение.Это позволяет мне полностью отказаться от использования RabbitMq и, при желании, активировать обработчики событий для каждого опубликованного сообщения.Кроме того, в нем отсутствуют конкретные имена классов событий, что позволяет мне использовать его для всех моих интеграционных тестов решений RabbitMq.

Можно сказать, что отсутствующий фрагмент был

var dynamicInvoke = d1.DynamicInvoke(o)

У меня есть«реальный» интерфейс, ретранслирующий вызовы RabbitMq / EasyNetQ для действующего приложения.

Спасибо за участие, @ensisNoctis!

  public class TestBusFront : IBusFront
  {
    private readonly Dictionary<string, List<Delegate>> _list;

    public TestBusFront()
    {
        _list=new Dictionary<string, List<Delegate>>();
    }
    public void Publish(object o)
    {
        var d = GetDelegateListForEvent(o.GetType().FullName);
        foreach (var d1 in d)
        {
            var dynamicInvoke = d1.DynamicInvoke(o);
            var task = (Task) dynamicInvoke;
            task.Wait();
        }
    }

    public void SubscribeAsync<T>(string s, Func<T, Task> handle)
    {
        var delegates = GetDelegateListForEvent(typeof(T).FullName);
        delegates.Add(handle);
    }

    private List<Delegate> GetDelegateListForEvent(string eventName)
    {
        if(!_list.ContainsKey(eventName))
            _list.Add(eventName,new List<Delegate>());

        return _list[eventName];
    }

    public void Dispose()
    {

    }
}
0 голосов
/ 04 октября 2018

Я заклятый враг, теряющий строгую типизацию в любом коде, и, по моему мнению, вам не следует пытаться решить свою проблему, создавая список «чего-либо».

С другой стороны, я нене знаете ваш код, и в случае, если это единственный путь, вы можете попробовать этот способ:

Func<int,    Task> f1 = i => Task.FromResult(i);
Func<string, Task> f2 = s => Task.FromResult(s);

var list = new List<object>
{
    f1,
    f2
};

foreach(var anything in list)
    switch(anything)
    {
        case Func<int,    Task> intFunction: intFunction(1); break;
        case Func<string, Task> strFunction: strFunction("text"); break;
        default: throw new ArgumentException($"I'm not prepared to deal with {anything} function prototype.");
    }

Этот код использует некоторые замечательные функции в C # 7, а именно Pattern Matching (переключение типа объекта)и встроенные переменные (int / strFunction).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...