如何使用 Net Framework 在 C# 中管理数千个级联事件?
How to manage thousands of cascade events in C# with Net Framework?
我在 .Net Framework 4.8 中有一个应用程序,其中有一个十进制值列表,我想在任何此列表成员的值发生变化时执行计算,代码工作正常,除非列表数据太大。
我可以使用哪种数据结构或方法来避免堆栈溢出?有解决这个问题的最佳实践或技巧吗?
我在一个小型控制台应用程序中准备并重现了错误:
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;
}
}
以上代码产生堆栈溢出异常。
我非常感谢能为我指明正确方向的任何提示或信息
这种带有“ContainerModel
”class 的模型在值更改时引发事件并不少见,即使我更喜欢通用实现。我还建议仅在值实际发生变化时才引发事件。这有助于避免不必要的更新。
然而,链接一长串对象的事件处理程序的模型可能不是一个好主意。如果您有需要监视更改的对象列表,最好创建一个新的集合类型来处理值的更改,并使用常规循环执行您需要的任何更新逻辑。
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];
}
}
}
}
如果您需要连接不同的集合,则向集合添加事件以在值范围发生更改时通知其他集合。
在不了解应用程序上下文的情况下,很难提供更多更好的建议。另一种方法是将关系建模为图形,并使用图形遍历算法来应用您想要的任何更新逻辑。这样你就可以在遍历时使用显式堆栈,并且只限于计算机的内存。
我在 .Net Framework 4.8 中有一个应用程序,其中有一个十进制值列表,我想在任何此列表成员的值发生变化时执行计算,代码工作正常,除非列表数据太大。
我可以使用哪种数据结构或方法来避免堆栈溢出?有解决这个问题的最佳实践或技巧吗?
我在一个小型控制台应用程序中准备并重现了错误:
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;
}
}
以上代码产生堆栈溢出异常。
我非常感谢能为我指明正确方向的任何提示或信息
这种带有“ContainerModel
”class 的模型在值更改时引发事件并不少见,即使我更喜欢通用实现。我还建议仅在值实际发生变化时才引发事件。这有助于避免不必要的更新。
然而,链接一长串对象的事件处理程序的模型可能不是一个好主意。如果您有需要监视更改的对象列表,最好创建一个新的集合类型来处理值的更改,并使用常规循环执行您需要的任何更新逻辑。
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];
}
}
}
}
如果您需要连接不同的集合,则向集合添加事件以在值范围发生更改时通知其他集合。
在不了解应用程序上下文的情况下,很难提供更多更好的建议。另一种方法是将关系建模为图形,并使用图形遍历算法来应用您想要的任何更新逻辑。这样你就可以在遍历时使用显式堆栈,并且只限于计算机的内存。