Как создать очередь делегатов событий, чтобы вы могли поднять их позже? - PullRequest
0 голосов
/ 12 апреля 2019

Можно ли добавить событие (или делегат) в список, чтобы я мог поднять четность на более позднем этапе; например, возможность кэшировать событие рейса, чтобы отложить его на более позднее время (например, буферизация событий).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelegateQueue {
    class Program {

        delegate void SomeTimeLaterDelegate(int myValue);
        static event SomeTimeLaterDelegate SomeTimeLater;
        static void Main(string[] args) {
            SomeTimeLater += new SomeTimeLaterDelegate(AnswerAnotherDay);
            SomeTimeLater += new SomeTimeLaterDelegate(ItIsPossible);
            SomeTimeLater += new SomeTimeLaterDelegate(HenceTheNeed);

            List<Delegate> delegates = new List<Delegate>();

            SomeTimeLater.Invoke(100); // <== I need to trap this call in a list that I can invoke later.
            ///both the function call and the value that I'm passing.
            ///the problem is that there are lots of different events and they must be invoked in the order
            ///that they occoured (i.e. no skipping in the buffer)

        }

        static void AnswerAnotherDay(int howManyDays) {
            Console.WriteLine($"I did this {howManyDays}, later. Hurray for procrastination!");
        }

        static void ItIsPossible(int numberOfPossibilities) {
        ///that there is in invocation list for the event
        ///which means that I would have to call each function in that list and pass them the value

        }

        static void HenceTheNeed(int needs) {
        ///hence the need to queue the Invocation of the event to a later point
        }
    }
}

Возможно, на событие есть несколько подписчиков, поэтому необходимо буферизовать со стороны издателя, а не со стороны подписчика.

Ответы [ 2 ]

1 голос
/ 12 апреля 2019

Вот буквальный пример того, что вы описываете:

class Program
{
    delegate void SomeTimeLaterDelegate(int myValue);
    delegate void SayHelloDelegate(string name);

    static event SomeTimeLaterDelegate SomeTimeLaterEvent;
    static event SayHelloDelegate SayHelloLaterEvent;
    static void Main(string[] args)
    {
        SomeTimeLaterEvent += new SomeTimeLaterDelegate(AnswerAnotherDay);
        SayHelloLaterEvent += new SayHelloDelegate(SayHello);

        var eventsToRaise = new Queue<Action>();
        eventsToRaise.Enqueue(() => SomeTimeLaterEvent.Invoke(100));
        eventsToRaise.Enqueue(() => SayHelloLaterEvent.Invoke("Bob"));
        eventsToRaise.Enqueue(() => SomeTimeLaterEvent.Invoke(200));
        eventsToRaise.Enqueue(() => SayHelloLaterEvent.Invoke("John"));

        while (eventsToRaise.Any())
        {
            var eventToRaise = eventsToRaise.Dequeue();
            eventToRaise();
            //or eventToRaise.Invoke();
        }

        Console.ReadLine();
    }

    static void AnswerAnotherDay(int howManyDays)
    {
        Console.WriteLine($"I did this {howManyDays}, later. Hurray for procrastination!");
    }

    static void SayHello(string name)
    {
        Console.WriteLine($"Hello, {name}");
    }
}

Вместо Queue<Delegate> это Queue<Action>.Action представляет вызов метода без передачи каких-либо параметров или получения возвращаемого значения.

Это может показаться нелогичным, поскольку вы передаете параметры.Но вы не передаете параметры в действия.Вы передаете параметры из тела действий.

Это может или не может помочь:

Когда мы объявляем

Action someAction = () => AnswerAnotherDay(5);

Это похоже на объявление метода, которыйвыглядит так:

void MyMethod()
{
    AnswerAnotherDay(5);
}

Метод вызывает другой метод и передает аргумент.Но MyMethod сам по себе не получает никаких аргументов.Когда мы объявляем встроенный метод таким образом, у него нет имени, поэтому он также называется анонимным методом.

Мы также можем объявить действие, которое принимает аргумент, например так:

Action<string> action = (s) => SayHelloLater(s);
action("Bob");

Причина, по которой я продемонстрировал использование Action без параметров, заключается в том, что вы сказали, что очередь может содержать события разных типов с разными параметрами.

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

Вот возможное упрощение: возможно, вы думаете о сценарии, в котором вам нужно вызывать события, но в этом примеремы можем сделать то же самое без событий, и это немного проще.

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

class Program
{
    static void Main(string[] args)
    {
        var eventsToRaise = new Queue<Action>();
        eventsToRaise.Enqueue(() => AnswerAnotherDay(100));
        eventsToRaise.Enqueue(() => SayHello("Bob"));
        eventsToRaise.Enqueue(() => AnswerAnotherDay(200));
        eventsToRaise.Enqueue(() => SayHello("John"));

        while (eventsToRaise.Any())
        {
            var eventToRaise = eventsToRaise.Dequeue();
            eventToRaise();
            //or eventToRaise.Invoke();
        }

        Console.ReadLine();
    }

    static void AnswerAnotherDay(int howManyDays)
    {
        Console.WriteLine($"I did this {howManyDays}, later. Hurray for procrastination!");
    }

    static void SayHello(string name)
    {
        Console.WriteLine($"Hello, {name}");
    }
}
0 голосов
/ 12 апреля 2019

Вот мой взгляд на вызов:

delegate void SomeTimeLaterDelegate(int myValue);
static event SomeTimeLaterDelegate SomeTimeLater;

static Queue<int> SomeTimeLaterQueue = new Queue<int>(); // Here we store the event arguments

static async Task Main(string[] args)
{
    SomeTimeLater += new SomeTimeLaterDelegate(AnswerAnotherDay); // Subscribe to the event
    await Task.Delay(100);
    OnSomeTimeLaterDefered(10); // Raise an defered event
    await Task.Delay(100);
    OnSomeTimeLaterDefered(20); // Raise another defered event
    await Task.Delay(100);
    OnSomeTimeLaterDefered(30); // Raise a third defered event
    await Task.Delay(100);
    OnSomeTimeLaterFlush(); // Time to raise the queued events for real!
}

static void OnSomeTimeLaterDefered(int value)
{
    SomeTimeLaterQueue.Enqueue(value);
}
static void OnSomeTimeLaterFlush()
{
    while (SomeTimeLaterQueue.Count > 0)
    {
        SomeTimeLater?.Invoke(SomeTimeLaterQueue.Dequeue());
    }
}

static void AnswerAnotherDay(int howManyDays)
{
    Console.WriteLine($"I did this {howManyDays}, later. Hurray for procrastination!");
}

Выход:

I did this 10, later. Hurray for procrastination!
I did this 20, later. Hurray for procrastination!
I did this 30, later. Hurray for procrastination!
...