How To Calculate String Formulas At Runtime On .Net

Bora Kaşmer
Geek Culture
Published in
5 min readNov 10, 2022

--

NASA in 1961(Image credits: J. R. Eyerman, via LIFE)

Hi, Today we will talk about how to calculate string formulas on runtime with C#.

In one project, we had to run thousands of math formulas to calculate some sizes of products. These formulas could be changed later and we could add new ones. Therefore, writing a static formula inside the class wouldn’t be true. We don’t have to rebuild our solution when we change the formula.

This is our example formula.

CMIW*CCL*(FG+CG)/10⁶+1+sqrt(3)

This is our example Formula model:

FormuleModel.cs: We will declare all parameters in formula as properties in this class. And when we calculate the formula, we will get property values from this class by using reflection.

public  class FormuleModel:IFormuleModel
{
public double CMIW { get; set; }
public int CCL { get; set; }
public int FG { get; set; }
public int CG { get; set; }
}

IFormuleModel.cs: We can get the value of the property by using the reflection library on FormuleModel class with this method. We can get the value of the parameters by their string name.

public interface IFormuleModel
{
public object this[string propertyName]
{
get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
}
}

Every formula which expresses a law of nature is a hymn of praise to God. — Maria Mitchell

Now we will create a string Extension static class. We will calculate string formulas with this extension.

CalculateFormulas() method has 2 parameters. One of them is the string formula and the second one is the parameters of the model. We have to fill in the model before calling this extension method. We will find all parameters in the formula with Regex.

We have to remove some specific Math terms like “sqrt, sin, cos, lim” from the finding parameter list. Because RegEx could not filter these words and it behaves as if these definitions were parameters. So we have to add the “Where” filter condition and remove these specific math terms “sqrt” for this example. We have to remove like “sin, tan, cos, lim” etc.. terms too if one of them is in the formula.

After regex determines the variables passed in the formula, the output variable looks like this => “CMIW, CCL, FG, CG

Formula: CMIW*CCL*(FG+CG)/1⁰⁶+1+sqrt(3)

We will put “{“ and “}” around every parameter and replace the formula. The formula looks like this =>“{0}*{1}*({2}+{3})/10⁶+1+sqrt(3)” We replaced all parameters with increment number.

We will separate all parameters with the Split(‘,’) function. And we will find the value of parameters with Reflection (“ prms[index] = model[prm]”) and put them into the object array “prms” with a foreach loop. Finding the value of parameters comes from, the IFormuleModel interface’s “get”, “set” properties. We will replace all parameters with their own values by using “String.Format(formula,prms)”. In the end, the formula looks like this =>”4.5*1*(4+3)/¹⁰⁶+1+sqrt(3)”. And finally, we will set Entity with the formula for calculating the result.

We will return result of calculation with “Entity.EvalNumerical()” method of AngouriMath library.

return (decimal)expr.EvalNumerical();

CalculateFormulas.cs: Custom string Extension class.

public static decimal CalculateFormulas(this string formule, IFormuleModel model)
{
String pattern = @"([A-Z]|[a-z])+([A-z]|[a-z]|\d|_)*";
String output = String.Join(",",
Regex.Matches(formule, pattern)
.OfType<Match>()
.Where(item => item.Value != "sqrt")
.Select(item => item.Value));
int i = 0;
output.Split(',').ToList().ForEach(item =>
{
formule = formule.Replace(item, "{" + i.ToString() + "}");
i++;
});
var varableArray = output.Split(',');
Object[] prms = new Object[varableArray.Length];
var index = 0;
varableArray.ToList().ForEach(prm =>
{
prms[index] = model[prm];
index++;
});
formule = String.Format(formule, prms);
Entity expr = formule;
return (decimal)expr.EvalNumerical();
}

This is our test formula. And we will fill our parameter’s model with test data.

We can call our Extension method “CalculateFormulas”, after all, strings. And for calculating the formula, we have to give the model as a parameter to this method.

Program.cs:

internal class Program
{
static void Main(string[] args)
{
String source = "CMIW*CCL*(FG+CG)/10^6+1+sqrt(3)";
FormuleModel model = new FormuleModel() { CMIW = 4.5, CCL = 1, FG = 4, CG = 3 };
var result = source.CalculateFormulas(model);
Console.WriteLine(result);
}
}

Result Screen: In the end, we got a result as seen below:

Success has a simple formula: Do your best, and people may like it. — Sam Ewing

Conclusion:

In this article, we tried to calculate a string formula without writing the specific logic codes into the program. Because writing thousands of formulas in the class is insane and managing is impossible. If somehow you change the codes, you have to build all project and publish it again. But if we save all formulas into the SQLDB or anywhere as a string, and calculate formulas dynamically, later we can change all of them by Admin screen without doing any extra effort and we can see the changing of all results suddenly.

Goodbye

See you until the next article.

“If you have read so far, first of all, thank you for your patience and support. I welcome all of you to my blog for more!”

Github: https://github.com/borakasmer/CalculateFormulasDynamically

Source:

--

--

Bora Kaşmer
Geek Culture

I have been coding since 1993. I am computer and civil engineer. Microsoft MVP. Software Architect(Cyber Security). https://www.linkedin.com/in/borakasmer/