tags: - EverSharpRunner - execution - api - csharp-integration
Using EverSharpRunner¶
The EverSharpRunner class is your main interface for executing EverSharp code from C#. This guide covers all its methods and properties.
Creating a Runner¶
Basic Instantiation¶
With Extension Functions¶
Add custom native functions:
var extensions = new Dictionary<string, Callable>
{
{ "$CustomFunction", new MyCustomFunction() }
};
var runner = new EverSharpRunner(extensions: extensions);
With Preloaded Libraries¶
Load common functions at startup:
var libraries = new List<string>
{
@"
function calculateTax(amount, rate) {
return amount * rate;
}
"
};
var runner = new EverSharpRunner(libraries: libraries);
Core Methods¶
Run()¶
Executes EverSharp statements and updates global variables.
Signature:
Example:
runner.Run(@"
premium = 1000;
discount = 0.15;
final = premium * (1 - discount);
");
var final = (decimal)runner.GlobalVariables["final"]; // 850
Use when:
- Executing multiple statements
- Updating variables
- Defining functions
- Running complete scripts
RunExpression()¶
Evaluates a single expression and returns its value directly.
Signature:
Example:
var result = runner.RunExpression("10 + 20 * 3"); // 70
var max = runner.RunExpression("$Max(100, 250)"); // 250
var greeting = runner.RunExpression("\"Hello, \" + \"World\""); // "Hello, World"
Use when:
- Evaluating single expression
- Getting immediate result
- No need to store in variable
Difference from Run(): | Feature | Run() | RunExpression() | |---------|-------|-----------------| | Input | Statements | Single expression | | Return value | void | Expression result | | Variables | Updates globals | No side effects (unless expression has them) | | Multiple statements | Yes | No |
Validate()¶
Checks syntax without executing code.
Signature:
Example:
var script = "x = 10; y = 20; z = x + y;";
var errors = runner.Validate(script);
if (!errors.Any())
{
Console.WriteLine("Script is valid");
runner.Run(script);
}
else
{
Console.WriteLine("Syntax errors:");
foreach (var error in errors)
{
Console.WriteLine($" - {error}");
}
}
Use when:
- Validating user-provided scripts
- Checking syntax before execution
- Providing immediate feedback in editors
ValidateExpression()¶
Checks expression syntax without evaluating.
Signature:
Example:
var expression = "x + y * 2";
var errors = runner.ValidateExpression(expression);
if (!errors.Any())
{
var result = runner.RunExpression(expression);
}
Environment Management¶
InitializeEnvironment()¶
Sets up constants and variables before execution.
Signature:
Example:
using Elements.Libs.Extensions.EverDictionaries;
// Constants (read-only in scripts)
var constants = new EverDictionary
{
{ "TAX_RATE", 0.08m },
{ "MAX_PREMIUM", 10000m },
{ "MIN_AGE", 18m }
};
// Variables (can be modified in scripts)
var variables = new EverDictionary
{
{ "age", 35m },
{ "coverage", 250000m }
};
runner.InitializeEnvironment(constants, variables);
runner.Run(@"
// Can read constants
tax = basePremium * TAX_RATE;
// Can modify variables
age = age + 1;
// Cannot modify constants (would create new local variable)
// TAX_RATE = 0.10; // Creates new local, doesn't change constant
");
When to use:
- Passing data from C# to EverSharp
- Setting up configuration values
- Providing context for scripts
SetExternalVariable()¶
Sets a single variable at runtime.
Signature:
Example:
// Set variables dynamically
runner.SetExternalVariable("userAge", 42m);
runner.SetExternalVariable("userName", "Alice");
runner.SetExternalVariable("activeDate", DateTime.Now);
runner.Run(@"
message = ""User "" + userName + "" is "" + userAge + "" years old"";
");
When to use:
- Setting individual variables after initialization
- Updating context during execution
- Injecting runtime values
Properties¶
HasErrors¶
Indicates whether errors occurred during last operation.
Type: bool
Example:
runner.Run(script);
if (runner.HasErrors)
{
Console.WriteLine("Execution failed");
}
else
{
Console.WriteLine("Execution successful");
}
Errors¶
Collection of error messages from last operation.
Type: IEnumerable<string>
Example:
runner.Run(invalidScript);
if (runner.HasErrors)
{
Console.WriteLine("Errors encountered:");
foreach (var error in runner.Errors)
{
Console.WriteLine($" - {error}");
}
}
GlobalVariables¶
All mutable variables created or modified during execution.
Type: EverDictionary
Example:
runner.Run("x = 10; y = 20; sum = x + y;");
// Access by key
var sum = (decimal)runner.GlobalVariables["sum"]; // 30
// Type-safe access (extension methods)
var x = runner.GlobalVariables.GetNumber("x");
var name = runner.GlobalVariables.GetStr("name");
var isActive = runner.GlobalVariables.GetBool("isActive");
GlobalConstants¶
All read-only constants defined during initialization.
Type: EverDictionary
Example:
var constants = new EverDictionary { { "PI", 3.14159m } };
runner.InitializeEnvironment(constants, new EverDictionary());
var pi = runner.GlobalConstants.GetNumber("PI"); // 3.14159
Globals¶
Combined view of all global variables and constants.
Type: EverDictionary
Example:
var allGlobals = runner.Globals;
foreach (var kvp in allGlobals)
{
Console.WriteLine($"{kvp.Key} = {kvp.Value}");
}
StandardOutput¶
Captured output from $Log() calls.
Type: string
Example:
runner.Run(@"
$Log(""Starting calculation"");
result = 10 + 20;
$Log(""Result: {0}"", result);
");
Console.WriteLine(runner.StandardOutput);
// Output:
// Starting calculation
// Result: 30
Type Conversions¶
EverDictionary Helper Methods¶
// Numeric values
var num = runner.GlobalVariables.GetNumber("premium");
decimal? nullableNum = runner.GlobalVariables.GetNumber("optional");
// String values
var str = runner.GlobalVariables.GetStr("name");
string? nullableStr = runner.GlobalVariables.GetStr("optional");
// Boolean values
var flag = runner.GlobalVariables.GetBool("isActive");
bool? nullableBool = runner.GlobalVariables.GetBool("optional");
// Objects (returns EverDictionary)
var dict = runner.GlobalVariables.GetDictionary("person");
var name = dict.GetStr("name");
// Arrays
var arr = runner.GlobalVariables.GetArray("numbers");
var first = (decimal)arr[0];
Manual Casting¶
// Direct cast (throws if type mismatch)
var num = (decimal)runner.GlobalVariables["value"];
var str = (string)runner.GlobalVariables["text"];
var date = (DateTime)runner.GlobalVariables["timestamp"];
// Safe cast (returns null if incompatible)
var num = runner.GlobalVariables["value"] as decimal?;
if (num.HasValue)
{
Console.WriteLine($"Number: {num.Value}");
}
Complete Example¶
using Elements.Libs.EverSharp;
using Elements.Libs.Extensions.EverDictionaries;
public class InsurancePremiumCalculator
{
private readonly EverSharpRunner runner;
public InsurancePremiumCalculator()
{
// Setup constants
var constants = new EverDictionary
{
{ "TAX_RATE", 0.08m },
{ "BASE_RATE", 0.01m },
{ "YOUTH_MULTIPLIER", 1.5m },
{ "SENIOR_MULTIPLIER", 1.25m }
};
// Load premium calculation library
var libraries = new List<string>
{
File.ReadAllText("scripts/premium-calculations.evs")
};
runner = new EverSharpRunner(libraries: libraries);
runner.InitializeEnvironment(constants, new EverDictionary());
}
public decimal CalculatePremium(int age, decimal coverageAmount)
{
// Set input variables
runner.SetExternalVariable("age", (decimal)age);
runner.SetExternalVariable("coverageAmount", coverageAmount);
// Execute calculation script
runner.Run(@"
premium = coverageAmount * BASE_RATE;
if (age < 25) {
premium = premium * YOUTH_MULTIPLIER;
} else if (age > 65) {
premium = premium * SENIOR_MULTIPLIER;
}
premium = premium * (1 + TAX_RATE);
premium = $Round(premium, 2);
");
// Check for errors
if (runner.HasErrors)
{
throw new Exception($"Calculation failed: {string.Join(", ", runner.Errors)}");
}
// Return result
return runner.GlobalVariables.GetNumber("premium") ?? 0;
}
public bool ValidateScript(string script)
{
var errors = runner.Validate(script);
if (errors.Any())
{
Console.WriteLine("Script validation failed:");
foreach (var error in errors)
{
Console.WriteLine($" - {error}");
}
return false;
}
return true;
}
}
// Usage
var calculator = new InsurancePremiumCalculator();
if (calculator.ValidateScript(userProvidedScript))
{
var premium = calculator.CalculatePremium(age: 35, coverageAmount: 250000m);
Console.WriteLine($"Premium: ${premium}");
}
Best Practices¶
1. Check Errors After Every Operation¶
runner.Run(script);
if (runner.HasErrors)
{
// Handle errors before accessing variables
LogErrors(runner.Errors);
return;
}
2. Validate User Scripts¶
// Always validate before executing user input
var errors = runner.Validate(userScript);
if (errors.Any())
{
return BadRequest(errors);
}
runner.Run(userScript);
3. Use Type-Safe Access¶
// Prefer
var value = runner.GlobalVariables.GetNumber("premium") ?? 0;
// Over
var value = (decimal)(runner.GlobalVariables["premium"] ?? 0m);
4. Initialize Environment Once¶
// Setup once at startup
runner.InitializeEnvironment(constants, initialVariables);
// Use SetExternalVariable for runtime updates
runner.SetExternalVariable("currentDate", DateTime.Now);
5. Capture Standard Output for Debugging¶
runner.Run(script);
if (!string.IsNullOrEmpty(runner.StandardOutput))
{
logger.Debug($"Script output: {runner.StandardOutput}");
}
Common Patterns¶
Pattern 1: Configuration-Driven Calculations¶
// Load configuration
var config = LoadConfiguration();
runner.InitializeEnvironment(config.Constants, config.Variables);
// Run calculation
runner.Run(config.CalculationScript);
var result = runner.GlobalVariables.GetNumber("result");
Pattern 2: Dynamic Rule Evaluation¶
foreach (var rule in rules)
{
runner.SetExternalVariable("ruleContext", ConvertToEverDictionary(context));
runner.Run(rule.Script);
if (runner.GlobalVariables.GetBool("rulePassed") == true)
{
ApplyRule(rule);
}
}
Pattern 3: Template-Based Generation¶
var template = LoadTemplate("premium-calculation");
var script = template.Replace("{{AGE}}", age.ToString())
.Replace("{{COVERAGE}}", coverage.ToString());
runner.Run(script);
return runner.GlobalVariables.GetNumber("result");
Next Steps¶
- Learn data types: Data Types
- Explore integration: Integration Guide
- See examples: Examples