Search code examples
c#eventsdata-structures.net-4.8

How to manage thousands of cascade events in C# with Net Framework?


I have an application in .Net Framework 4.8 where i have a list of decimal values, i want to perform a calculation when there is a value change in any of this list members, the code works fine except when the list of data is too large.

Which data structure or approach could i use to avoid Stack Overflow? are there any best practices or tips to solve this problematic?

i prepared and reproduced the error in a small console application:

class Program
{
    static void Main(string[] args)
    {

        List<ContainerModel> containerModels = new List<ContainerModel>();

        PopulateModel(containerModels, 25000);

        SubscribeVariables(containerModels);

        containerModels.First().Index = 5000;

        foreach (ContainerModel item in containerModels)
        {
            Console.WriteLine(item.Index);
        }

        Console.ReadLine();
    }

    private static void PopulateModel(List<ContainerModel> containerModels, int numberOfVariables)
    {
        for (int i = 0; i < numberOfVariables; i++)
        {
            containerModels.Add(
                new ContainerModel()
                {
                    Index = i
                }
            );
        }
    }

    private static void SubscribeVariables(List<ContainerModel> containerModels)
    {
        for (int i = 0; i < containerModels.Count() - 1 ; i++)
        {
            containerModels[i].ValueChanged += containerModels[i + 1].C_ValueChanged;
        }
    }
}

public class ContainerModel
{
    public event EventHandler<decimal> ValueChanged;

    private decimal _index;
    public decimal Index
    {
        get => _index;
        set
        {
            _index = value;

            ValueChanged?.Invoke(this, value);

        }
    }
    public void C_ValueChanged(object sender, decimal value)
    {
        Index += value;
    }
}

The code above produces a stack overflow exception.

I appreciate so much any tips or information to point me in the right direction


Solution

  • This kind of model with a "ContainerModel" class that raises an event when a value is changed is not that unusual, even if I would prefer a generic implementation. I would also suggest only raising the event if the value has actually changed. This helps avoiding unnecessary updates.

    A model that chains event handlers of a long list of objects is probably not a good idea however. If you have lists of objects that need to be monitored for change it is probably better to create a new collection type handles changes of a value with a regular loop that does whatever update logic you need.

    public class MyCollection
    {
        private List<decimal> values = new ();
        public void Add(decimal v) => values.Add(v);
    
        public decimal this[int index]
        {
            get => values[index];
            set
            {
                values[index] = value;
                for (int i = index+1; i < values.Count; i++)
                {
                    values[i] += values[i - 1];
                }
            }
        }
    }
    

    If you need to connect different collections then add events to the collection to inform the other collections when a range of values have been changed.

    It is quite difficult to provide more a better suggestion without knowing the context of the application. Another approach is to model the relationships as a graph and use graph traversal algorithms to apply whatever update logic you want. That way you can use an explicit stack when doing the traversal, and only be limited to the memory of the computer.