Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Events with Memory in MC++

0.00/5 (No votes)
1 Jun 2004 1  
An article on adding memory to events using Managed C++.

Introduction

Delegates are a nice feature of .NET that really make coding callbacks simple. This article is not going to describe how to create delegates and events - there are many other articles on CodeProject that give you this information. One thing that delegates can't do is to remember when an event is invoked so that the data can be sent to any new delegates that get added to the event.

Background

This problem was given to me at work because events were being triggered before all of the parts of the system were created and attached. This lead to some components not having the correct data. This needed to be resolved in a way that was the most generic.

Creating Event Accessors

The first step is to create some delegates and a class with events for them. For the events, the normal declaration was replaced by the accessors for the events.

__event void add_E(MyDel* p)
{
    Console::WriteLine("Add E");
    pE = static_cast<MyDel*> (Delegate::Combine(pE,p));
}

__event void remove_E(MyDel* p)
{
    Console::WriteLine("Remove E");
    pE = static_cast<MYDEL*> (Delegate::Remove(pE, p));
}

__event void raise_E()
{
    Console::WriteLine("Raise E");
    if (pE != 0)
        pE->Invoke();
}

This creates an event named E. Then a class was created to receive the events.

public __gc class EventReceiver
{
public:
    void H1() 
    {
        Console::WriteLine("EventReceiver - H1");
    }

    int H2(int i, float f)
    {
        Console::WriteLine("EventReceiver - H2 with args {0} and {1}", 
                                          i.ToString(), f.ToString());
        return 0;
    }
};

Then in the main of this sample, instances of the two classes were created and then delegates attached to the event E. So far, this is just like any other delegate/event project if you were going to create the accessors manually. Of course, the compiler normally creates the accessors for you automatically.

EventSource* pE = new EventSource();
EventReceiver* pR = new EventReceiver();
EventReceiver2* pR2 = new EventReceiver2();

// hook event handlers for pR

Console::WriteLine("EventReceiver - hooking events");
pE->E += new MyDel(pR, &EventReceiver::H1);
pE->E2 += new MyDel2(pR, &EventReceiver::H2);

// raise the E event

pE->E();

The next step is to give the event a bit of memory to remember when it was raised. If the delegate had variables, then those would have to be saved also. For the event E in this sample, only a bool to say it had been invoked is needed. So, two changes to the code are required - first to the raise_ accessor and then to the add_ accessor.

__event void add_E(MyDel* p)
{
    Console::WriteLine("Add E");
    pE = static_cast<MyDel*> (Delegate::Combine(pE,p));
    if(m_eInvoked == true)
        p->Invoke();
}

__event void raise_E()
{
    Console::WriteLine("Raise E");
    if (pE != 0)
    {
        m_eInvoked = true;
        pE->Invoke();
    }
}

Using this method, the programmer can control which events get this memory enhancement and which do not. For events that are the typical "fire-and-forget" type of events, this might not be needed. For others things, a "fire-and-forget" type of event might reset other variables for other events. An example of this might be paper being inserted into a printer, one event might be to send what paper is available in the printer and another event could be a signal that paper has been removed. The paper removal event could clear a stored variable for what paper is available.

The sample code expands this sample to two receiving instances and two events.

The C# Difference

I looked into using event accessors in C# as well as MC++. I setup class and accessor functions for adding and removing delegates, and then went to add an accessor for raising the event. The compiler would not let me add a function for raising the event. I found this to be strange and puzzling because it is showing that MC++ has more functionality than C#. After looking into it some more, I found that you have to use a custom function to raise the event instead of an accessor. After this was in place, the C# code looked similar to the MC++ code. The code is included in this article but not in the download unless people want it included later.

public class EventSource 
{
    // private variables for E event

    private    MyDel pE;
    private bool m_eInvoked;

    public EventSource()
    {
        m_eInvoked=false;
    }

    public event MyDel E
    {
        add
        {
            Console.WriteLine("Add E");
            pE += value;
            if(m_eInvoked==true)
                value(); 
        }
        remove
        {
            Console.WriteLine("Remove E");
            pE -= value;
        }
    }
    public void RaiseE()
    {
        m_eInvoked = true;
        if(pE != null)
            pE();
    }
};

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here