H everyone, So first, what I'm trying to achieve: In my game, a grand-strategy inspired by Civ and CK2, time passes as days go buy (appr. 1 sec = 1 day) and each day, certain things can happen, for example people age and characters are doing things. So in a gameObject called GameManager I handle the general time passing (relevant snippet from the whole script): Code (CSharp): public int daysPassed; int currentDay; int currentMonth; int currentYear; int currentYearDay; // this goes from 1 to 360 float gameSpeed; // This shows the number of secs between days, so the higher, the slower! public delegate void myDelegate(); public Dictionary<int, myDelegate> yearDayEvents = new Dictionary<int, myDelegate> (); // for yearly recurring events public Dictionary<int, myDelegate> totalDaysEvents = new Dictionary<int, myDelegate> (); // for only happening once events IEnumerator TimePassing () { while(true) { daysPassed++; currentDay++; currentYearDay++; if (currentDay > 30) { currentMonth++; if (currentMonth > 12) { currentYear++; currentMonth = 1; currentYearDay = 1; } currentDay = 1; } yearDayEvents[currentYearDay](); // here fire events that trigger once per year if (totalDaysEvents.ContainsKey(daysPassed)) { totalDaysEvents[daysPassed](); // all added events for that day fire here totalDaysEvents.Remove(daysPassed); } timeLabel.text = currentDay.ToString("00") + "." + currentMonth.ToString("00") + "." + currentYear.ToString("0000"); yield return new WaitForSeconds(gameSpeed); } } public void StartTime() { gameSpeed = 1f; daysPassed = 0; currentYear = startYear; currentMonth = 1; currentDay = 1; currentYearDay = 1; for (int i = 1; i <= 360; i++) { if(!yearDayEvents.ContainsKey(i)) { yearDayEvents[i] = new myDelegate(FillerFunction); } } StartCoroutine(TimePassing()); } the relevant object here is the totalDaysEvents which is a dictionary having as a key an integer that is the number of the day since the game started and as value a delegate which SHOULD contain all events that will trigger on that day. Here is the function from the character.cs script, in which I try to add functions to the delegates: Code (CSharp): public void QueueDoSomething () { int daysToNextDoing = 5; // will be replaced by a function int nextDay = gameManager.daysPassed + daysToNextDoing; if (gameManager.totalDaysEvents.ContainsKey(nextDay)) { var myDelegate = gameManager.totalDaysEvents[nextDay]; myDelegate += this.DoSomething; } else { var myDelegate = new GameManager.myDelegate(this.DoSomething); gameManager.totalDaysEvents.Add(nextDay, myDelegate); } } public void DoSomething () { if (verbose) { Debug.Log("I'm thinking about doing something :-)"); } QueueDoSomething(); } So, now to the thing that won't work: My delegates seem always only to hold one function and never multiple. So I guess I must be doing something wrong when initializing the delegate? Maybe I do this completely wrong and there is a much easier way to do this? (I'm new to Unity so feel free to give me advice ) Thanks in advance, I'm really lost here, Cheers, Ray
Well, I was stupid. Delegates aren't mutable, so I had to add the line Code (CSharp): gameManager.totalDaysEvents[nextDay] = myDelegate; Hope this helps if anyone else stumbles upon this problem at some point.
Well technically a delegate is a reference to method/s, not a method itself (delegates are technically multicast, so it's a collection of method references). So to mutate a delegate would be to mutate what it is referencing, rather than mutate the methods that are referenced. It'd be like mutating an array... mutating the array doesn't mutate the element. It mutates what the array has in it.
I'm pretty sure delegates don't have to be multicast. They will simply create a multicast delegate if you use the + operator on two regular delegates. And yes, delegates are immutable, so when you "add" a regular delegate to an existing multicast delegate, it creates a new object which is the multicast delegate that contains all the old calls plus the new one. In the OP's case, if you don't reassign the new object back into the array, the changes will just get thrown away. As for mutable methods .. you can use Expression<Action> and related types to build code programmatically. The Expression can then be compiled into a delegate. If you have the original Expression, then you can "mutate" the code and then recompile. Of course, mutate is probably the wrong word to use here since Expression is also immutable. Adding expressions to an expression tree creates a new tree.
All concrete delegate types inherit from System.MulticastDelegate. You can investigate the inheritance chain of any delegate you create yourself, or a delegate that is in the framework (like System.Action) and see that it'll directly inherit from MultcastDelegate, followed by Delegate, followed by Object. The language has no way of inheriting directly from Delegate, and I'm not sure exactly why they broke its logic into 2 classes like that either. I read somewhere that Microsoft originally had some idea to use it for, but then never did it.