Problem with static class data member...

I am trying to implement a message map like system as in Microsoft Foundation Classes for Visual Studio in order to avoid having links to my various gameobjects all over the place, that is required in order to use the standard Unity SendMessage(…) function. It seems to much like spaghetti code to gameobject links all over the place.

I am trying to implement it in a base class that adds to the functionality of the MonoBehavior class.

Then all my other script class inherit the new base class rather than MonoBehavior.

The idea is to have a static array in which to which you add entries along the following lines, with my function public static void RegisterMessageReceiver(GameObject gameobj, string strFuncName) being used to add the message map entries.

±----------------±-----------------+
| FuncName1 | gameObject1 |
| | gameObject2 |
| | gameObject3 |
| | gameObject4 |
| | gameObject5 |
| | gameObject6 |
±----------------±-----------------+
| FuncName2 | gameObject1 |
| | gameObject2 |
| | gameObject5 |
| | gameObject6 |
±----------------±-----------------+
| FuncName2 | gameObject1 |
| | gameObject2 |
| | gameObject5 |
±----------------±-----------------+

Then you call the function PostMessage(“FuncName”, ParamValue) and it goes through the above array, finds the matching function name and calls Unity SendMessage(…) on all the gameObjects registered for that function.

My problem is that static in C# does not seem to mean quite the same thing as it does in C++ / Microsoft Foundation Classes.

Across all my game objects I am adding 4 entries into the above array via RegisterMessageReceiver(…), with a call to DumpMessageMap() after each, to see what is in the array.

However I am not seeing 4 entries in the array after one of my calls to DumpMessageMap(). Rather it appears that there are two different copies of ‘private static ArrayList m_arrayRegisteredMessages = new ArrayList();’, each with 2 entries in it. The end result is that I am getting the error message “SendMessage SaveChangePattern has no receiver!”

Does the keyword static, as applied to class members, have exactly the same meaning in C# as it does in C++?

In C++, if you have a static class member, then all objects no matter where and when they are instantiated, all refer to the same location in computer memory when you reference that static class member.

public class MessageEntry
{
    private string m_strFuncName;
    private ArrayList m_arrayReceivers = new ArrayList();

    public MessageEntry()
    {
    }

    public MessageEntry(string strFuncName, GameObject gameobj)
    {
        m_strFuncName = strFuncName;
        m_arrayReceivers.Add(gameobj);
    }

    public string GetFuncName()
    {
        return m_strFuncName;
    }

    public void AddReceiver(GameObject gameobjRec)
    {
        m_arrayReceivers.Add (gameobjRec);
    }

    public void PostMessage(int nParam = -1)
    {
        for (int nI = 0; nI < m_arrayReceivers.Count; nI++)
        {
            if (nParam > -1)
                ((GameObject)m_arrayReceivers [nI]).SendMessage(m_strFuncName, nParam);
            else
                ((GameObject)m_arrayReceivers [nI]).SendMessage(m_strFuncName);
        }
    }

    public void PostMessage(bool bParam)
    {
        for (int nI = 0; nI < m_arrayReceivers.Count; nI++)
        {
            ((GameObject)m_arrayReceivers [nI]).SendMessage(m_strFuncName, bParam);
        }
    }

    public void Dump()
    {
        Debug.Log(m_strFuncName);
        for (int nI = 0; nI < m_arrayReceivers.Count; nI++)
        {
            Debug.Log(((GameObject)m_arrayReceivers[nI]).name);
        }
        Debug.Log("--------------------------------------");
    }

}

public class McCormickMonoBehaviourBase : MonoBehaviour
{
    private static ArrayList m_arrayRegisteredMessages = new ArrayList();

    private static int FindFuncName(string strFuncName)
    {
        int nI = -1;
   
        for (nI = 0; nI < m_arrayRegisteredMessages.Count; nI++)
        {
            if (((MessageEntry)m_arrayRegisteredMessages[nI]).GetFuncName() == strFuncName)
                break;
        }
        if (nI == m_arrayRegisteredMessages.Count)
            nI = -1;
       
        return nI;
    }

    public static void RegisterMessageReceiver(GameObject gameobj, string strFuncName)
    {
        int nI = FindFuncName(strFuncName);

        if (nI >= 0)
        {
            ((MessageEntry)m_arrayRegisteredMessages[nI]).AddReceiver(gameobj);
        }
        else
        {
            MessageEntry messageentry = new MessageEntry(strFuncName, gameobj);
            m_arrayRegisteredMessages.Add(messageentry);
        }
    }

    public static void PostMessage(string strFuncName, int nParam)
    {
        int nI = FindFuncName(strFuncName);

        if (nI > -1)
        {
            ((MessageEntry)m_arrayRegisteredMessages[nI]).PostMessage(nParam);
        }
    }

    public static void PostMessage(string strFuncName, bool bPraram)
    {
        int nI = FindFuncName(strFuncName);

        if (nI > -1)
        {
            ((MessageEntry)m_arrayRegisteredMessages[nI]).PostMessage(bPraram);
        }
    }

    public static void DumpMessageMap()
    {
        for (int nI = 0; nI < m_arrayRegisteredMessages.Count; nI++)
        {
            ((MessageEntry)m_arrayRegisteredMessages[nI]).Dump();
        }
        Debug.Log("XXXXXXXXXXXXXXXXXXXXXXXXX");
        Debug.Log("XXXXXXXXXXXXXXXXXXXXXXXXX");
    }

    protected virtual void DoUpdate()
    {
    }

    protected virtual void DoStart()
    {
    }

    void Start()
    {
        DoStart();
    }

    void Update()
    {
        DoUpdate();
    }

}

admittedly I skimmed, but my first thought is “why not just use events”? either c# event or unityevent.

As LeftyRighty said, use events for this. You’re essentially reinventing events. You’re also building this on top of SendMessage, which is a slow and hard to debug way of communicating.

You’re also using an ArrayList for your messages. You should avoid ArrayList at any cost - use a List instead. If m_arrayRegisteredMessages was a List in your code, it’d do exactly the same thing as now, but you’d be able to get rid of all of the casts to MessageEntry that’s in every single one of your methods.

Also note that Unity does some smart optimization, and only calls Update on the MonoBehaviours that implement them. If you have a base class that defines Update, and inherit from it in every of your scripts, you’ll get the overhead of Update being called on every frame even if you’re not using it. It’s not a big performance sink, but be aware of it.

A static variable in C# defines a single, global variable. There’s only one of your m_arrayRegisteredMessages. It is possible to replace it with a different ArrayList, but it doesn’t look like you’re doing that.

I’m not familiar with exactly how C++ does static variables, but for a reference type in C#, the static variable is simply a global pointer to some object. You can replace what object it points to, unless the object is readonly. It’s pretty much the same thing as what you’re describing for C++.