using System;
using System.Collections.Generic;
using System.Data;
namespace Compute
{
public class Formula
{
public string Name { get; set; }
public string Expression { get; set; }
public decimal? Value { get; set; }
public List<Formula> Dependencies { get; set; }
public decimal Calculate()
{
if (Value.HasValue) // 如果已经计算过,直接返回
{
return Value.Value;
}
else
{
foreach (Formula dependency in Dependencies)
{
dependency.Calculate(); // 计算依赖项的值
}
var expression = Expression;
foreach (var dependency in Dependencies)
{
expression = expression.Replace(dependency.Name, dependency.Value.ToString());
}
if (string.IsNullOrWhiteSpace(expression))
return 0;
else
Value = Convert.ToDecimal(new DataTable().Compute(expression, null));
return Value.Value;
}
}
}
}
public decimal Calculate(HashSet<string> visitedFormulas = null)
{
if (Value.HasValue)
{
return Value.Value;
}
else
{
visitedFormulas ??= new HashSet<string>(); // 创建一个空的 HashSet
if (visitedFormulas.Contains(Name)) // 检查是否存在循环引用
{
// 处理循环引用的逻辑,例如记录错误日志并返回一个默认值
Console.WriteLine($"循环引用: {Name}");
return 0;
}
visitedFormulas.Add(Name); // 将当前公式的名称添加到已访问的集合中
foreach (Formula dependency in Dependencies)
{
dependency.Calculate(visitedFormulas); // 传递已访问的集合给依赖项的计算方法
}
var expression = Expression;
foreach (var dependency in Dependencies)
{
expression = expression.Replace(dependency.Name, dependency.Value.ToString());
}
if (string.IsNullOrWhiteSpace(expression))
return 0;
else
Value = Convert.ToDecimal(new DataTable().Compute(expression, null));
visitedFormulas.Remove(Name); // 在计算完当前公式后,将其从已访问的集合中移除
return Value.Value;
}
}
Formula类表示一个公式,包含公式的名称、表达式、值以及依赖项列表。Calculate方法用于计算公式的值,它会递归计算所有依赖项的值,并在所有依赖项的值都已计算完成后,计算当前公式的值。在计算公式值的过程中,如果某个公式的值已经计算过,则直接返回该值,以避免无限递归。