Environment Setup¶
Passing data between C# and EverSharp, including type conversions and environment initialization.
Overview¶
EverSharp and C# exchange data through the EverDictionary type, which provides a bridge between .NET types and EverSharp's internal representation.
EverDictionary¶
EverDictionary is a dictionary type from the Elements.Libs.Extensions.EverDictionaries namespace that facilitates data exchange.
using Elements.Libs.Extensions.EverDictionaries;
var dict = new EverDictionary
{
["name"] = "John Smith",
["age"] = 35,
["premium"] = 1200.50m
};
Type Conversions¶
C# to EverSharp¶
When passing data from C# to EverSharp:
| C# Type | EverSharp Type | Notes |
|---|---|---|
decimal |
decimal |
Direct mapping |
int, long, float, double |
decimal |
Auto-converted to decimal |
string |
string |
Direct mapping |
bool |
boolean |
Direct mapping |
DateTime |
DateTime |
Direct mapping |
DateOnly |
DateOnly |
Direct mapping |
null |
null |
Direct mapping |
Dictionary<string, object> |
Instance |
Converted to EverSharp object |
EverDictionary |
Instance |
Preferred way to pass objects |
List<object> |
InstanceArray |
Converted to EverSharp array |
object[] |
InstanceArray |
Converted to EverSharp array |
Example:
var runner = new EverSharpRunner();
// Numeric types - all convert to decimal
runner.SetExternalVariable("decimalValue", 100.5m);
runner.SetExternalVariable("intValue", 42);
runner.SetExternalVariable("doubleValue", 3.14);
// String
runner.SetExternalVariable("name", "Alice");
// Boolean
runner.SetExternalVariable("isActive", true);
// DateTime
runner.SetExternalVariable("effectiveDate", DateTime.Parse("2024-01-15"));
// Null
runner.SetExternalVariable("optional", null);
// Object (Dictionary)
var person = new EverDictionary
{
["firstName"] = "John",
["lastName"] = "Smith",
["age"] = 35
};
runner.SetExternalVariable("person", person);
// Array
var numbers = new object[] { 1, 2, 3, 4, 5 };
runner.SetExternalVariable("numbers", numbers);
EverSharp to C¶
When retrieving data from EverSharp:
| EverSharp Type | C# Type | How to Retrieve |
|---|---|---|
decimal |
decimal |
Convert.ToDecimal(value) |
string |
string |
(string)value or .ToString() |
boolean |
bool |
Convert.ToBoolean(value) |
null |
null |
Check == null |
DateTime |
DateTime |
(DateTime)value |
DateOnly |
DateOnly |
(DateOnly)value |
Instance |
EverDictionary |
Cast or use helper methods |
InstanceArray |
object[] |
Cast or use helper methods |
Example:
runner.Run(@"
count = 10;
name = 'Alice';
isValid = true;
amount = 1200.50;
person = { firstName: 'John', age: 30 };
items = [1, 2, 3];
");
// Retrieve simple types
var count = Convert.ToDecimal(runner.GlobalVariables["count"]);
var name = (string)runner.GlobalVariables["name"];
var isValid = Convert.ToBoolean(runner.GlobalVariables["isValid"]);
var amount = Convert.ToDecimal(runner.GlobalVariables["amount"]);
// Retrieve object
var person = runner.GlobalVariables.GetDictionary("person");
var firstName = person["firstName"];
var age = Convert.ToInt32(person["age"]);
// Retrieve array
var items = runner.GlobalVariables.GetArray("items");
var firstItem = Convert.ToDecimal(items[0]);
InitializeEnvironment¶
The InitializeEnvironment method sets up the global environment with constants and variables.
Method Signature¶
Parameters:
constants: Read-only values accessible in EverSharp (cannot be modified)variables: Read-write values accessible in EverSharp (can be modified)
Constants vs Variables¶
Constants:
- Set from C# before script execution
- Read-only in EverSharp (cannot be reassigned)
- Useful for configuration values, rates, limits
Variables:
- Set from C# before script execution
- Can be modified by EverSharp scripts
- Changes are visible to C# after execution
Example: Constants¶
var constants = new EverDictionary
{
["TAX_RATE"] = 0.08m,
["MAX_COVERAGE"] = 1000000m,
["MIN_AGE"] = 18,
["COMPANY_NAME"] = "Acme Insurance"
};
var variables = new EverDictionary();
runner.InitializeEnvironment(constants, variables);
// In EverSharp, constants are read-only
runner.Run(@"
amount = 1000;
tax = amount * TAX_RATE; // Can read TAX_RATE
total = amount + tax;
// This would cause an error:
// TAX_RATE = 0.10; // Cannot modify constant
");
var total = Convert.ToDecimal(runner.GlobalVariables["total"]);
Console.WriteLine($"Total: {total}"); // 1080
Example: Variables¶
var constants = new EverDictionary();
var variables = new EverDictionary
{
["policyNumber"] = "POL-12345",
["premium"] = 1200m,
["status"] = "Pending"
};
runner.InitializeEnvironment(constants, variables);
// EverSharp can modify variables
runner.Run(@"
if (premium > 1000) {
status = 'Approved';
discountRate = 0.10;
discount = premium * discountRate;
finalPremium = premium - discount;
}
");
// Get updated values from C#
var status = (string)runner.GlobalVariables["status"];
var finalPremium = Convert.ToDecimal(runner.GlobalVariables["finalPremium"]);
Console.WriteLine($"Status: {status}"); // Approved
Console.WriteLine($"Final Premium: {finalPremium}"); // 1080
Working with Objects¶
Passing Objects to EverSharp¶
var customer = new EverDictionary
{
["id"] = 1001,
["name"] = "Alice Johnson",
["age"] = 32,
["address"] = new EverDictionary
{
["street"] = "123 Main St",
["city"] = "Springfield",
["zip"] = "12345"
}
};
var variables = new EverDictionary
{
["customer"] = customer
};
runner.InitializeEnvironment(new EverDictionary(), variables);
runner.Run(@"
customerName = customer.name;
city = customer.address.city;
// Modify object
customer.age = 33;
customer.status = 'Active';
");
// Get updated object
var updatedCustomer = runner.GlobalVariables.GetDictionary("customer");
var age = Convert.ToInt32(updatedCustomer["age"]); // 33
var status = (string)updatedCustomer["status"]; // "Active"
Retrieving Objects from EverSharp¶
runner.Run(@"
policy = {
id: 12345,
premium: 1200,
holder: {
name: 'John Smith',
age: 35
}
};
");
// Retrieve nested object
var policy = runner.GlobalVariables.GetDictionary("policy");
var policyId = Convert.ToInt32(policy["id"]);
var premium = Convert.ToDecimal(policy["premium"]);
var holder = policy.GetDictionary("holder");
var holderName = (string)holder["name"];
var holderAge = Convert.ToInt32(holder["age"]);
Console.WriteLine($"Policy {policyId}: ${premium}");
Console.WriteLine($"Holder: {holderName}, Age: {holderAge}");
Working with Arrays¶
Passing Arrays to EverSharp¶
var policies = new object[]
{
new EverDictionary
{
["id"] = 1,
["premium"] = 1200m,
["status"] = "Active"
},
new EverDictionary
{
["id"] = 2,
["premium"] = 850m,
["status"] = "Pending"
}
};
var variables = new EverDictionary
{
["policies"] = policies
};
runner.InitializeEnvironment(new EverDictionary(), variables);
runner.Run(@"
activePolicies = policies.Filter((p) => p.status == 'Active');
totalPremium = policies
.Map((p) => p.premium)
.ReduceToNum((sum, p) => sum + p, 0);
");
var total = Convert.ToDecimal(runner.GlobalVariables["totalPremium"]);
Console.WriteLine($"Total Premium: ${total}"); // 2050
Retrieving Arrays from EverSharp¶
runner.Run(@"
numbers = [1, 2, 3, 4, 5];
items = [
{ id: 1, name: 'Item A' },
{ id: 2, name: 'Item B' }
];
");
// Retrieve simple array
var numbers = runner.GlobalVariables.GetArray("numbers");
foreach (var num in numbers)
{
Console.WriteLine(Convert.ToDecimal(num));
}
// Retrieve array of objects
var items = runner.GlobalVariables.GetArray("items");
foreach (var item in items)
{
var itemDict = item.ToEverDictionary();
var id = Convert.ToInt32(itemDict["id"]);
var name = (string)itemDict["name"];
Console.WriteLine($"{id}: {name}");
}
Practical Examples¶
Example 1: Policy Calculator with Input/Output¶
public class PolicyCalculator
{
private readonly EverSharpRunner runner;
public PolicyCalculator(string rulesScript)
{
runner = new EverSharpRunner();
runner.Run(rulesScript);
}
public PolicyResult Calculate(PolicyInput input)
{
// Set up constants
var constants = new EverDictionary
{
["BASE_RATE"] = 2.5m,
["YOUNG_DRIVER_FACTOR"] = 1.5m,
["SENIOR_FACTOR"] = 1.3m
};
// Set up variables
var variables = new EverDictionary
{
["coverageAmount"] = input.CoverageAmount,
["age"] = input.Age,
["hasDiscount"] = input.HasDiscount
};
runner.InitializeEnvironment(constants, variables);
// Execute calculation
runner.Run(@"
basePremium = coverageAmount * BASE_RATE / 1000;
if (age < 25) {
ageFactor = YOUNG_DRIVER_FACTOR;
} else if (age >= 65) {
ageFactor = SENIOR_FACTOR;
} else {
ageFactor = 1.0;
}
adjustedPremium = basePremium * ageFactor;
if (hasDiscount) {
discount = adjustedPremium * 0.10;
} else {
discount = 0;
}
finalPremium = adjustedPremium - discount;
");
// Extract results
return new PolicyResult
{
BasePremium = Convert.ToDecimal(runner.GlobalVariables["basePremium"]),
AgeFactor = Convert.ToDecimal(runner.GlobalVariables["ageFactor"]),
Discount = Convert.ToDecimal(runner.GlobalVariables["discount"]),
FinalPremium = Convert.ToDecimal(runner.GlobalVariables["finalPremium"])
};
}
}
Example 2: Batch Processing¶
public class BatchProcessor
{
public List<Result> ProcessPolicies(List<Policy> policies)
{
var runner = new EverSharpRunner();
// Load processing rules
runner.Run(@"
function processPolicy(policy) {
result = {
id: policy.id,
originalPremium: policy.premium
};
if (policy.yearsActive >= 5) {
result.discount = policy.premium * 0.10;
} else {
result.discount = 0;
}
result.finalPremium = policy.premium - result.discount;
return result;
}
");
var results = new List<Result>();
foreach (var policy in policies)
{
// Set policy as variable
var policyDict = new EverDictionary
{
["id"] = policy.Id,
["premium"] = policy.Premium,
["yearsActive"] = policy.YearsActive
};
runner.SetExternalVariable("currentPolicy", policyDict);
// Process
var resultObj = runner.RunExpression("processPolicy(currentPolicy)");
var resultDict = ((EverDictionary)resultObj);
results.Add(new Result
{
PolicyId = Convert.ToInt32(resultDict["id"]),
OriginalPremium = Convert.ToDecimal(resultDict["originalPremium"]),
Discount = Convert.ToDecimal(resultDict["discount"]),
FinalPremium = Convert.ToDecimal(resultDict["finalPremium"])
});
}
return results;
}
}
Example 3: Dynamic Configuration¶
public class DynamicRuleEngine
{
private readonly EverSharpRunner runner;
public DynamicRuleEngine()
{
runner = new EverSharpRunner();
}
public void LoadConfiguration(AppConfig config)
{
var constants = new EverDictionary
{
["MIN_AGE"] = config.MinAge,
["MAX_AGE"] = config.MaxAge,
["TAX_RATE"] = config.TaxRate,
["BASE_RATE"] = config.BaseRate,
["DISCOUNT_THRESHOLD"] = config.DiscountThreshold,
["DISCOUNT_RATE"] = config.DiscountRate
};
runner.InitializeEnvironment(constants, new EverDictionary());
// Load rules that use the configuration
runner.Run(@"
function calculatePremium(amount, age) {
if (age < MIN_AGE || age > MAX_AGE) {
return null;
}
premium = amount * BASE_RATE / 1000;
if (premium >= DISCOUNT_THRESHOLD) {
discount = premium * DISCOUNT_RATE;
premium = premium - discount;
}
tax = premium * TAX_RATE;
return premium + tax;
}
");
}
public decimal? Calculate(decimal amount, int age)
{
runner.SetExternalVariable("amount", amount);
runner.SetExternalVariable("age", age);
var result = runner.RunExpression("calculatePremium(amount, age)");
if (result == null)
{
return null;
}
return Convert.ToDecimal(result);
}
}
Helper Methods¶
EverDictionary Helper Methods¶
// Get nested dictionary
var address = customer.GetDictionary("address");
// Get array
var items = variables.GetArray("items");
// Convert object to EverDictionary
var dict = obj.ToEverDictionary();
// Check if key exists
bool hasKey = dict.ContainsKey("propertyName");
// Get with default value
var value = dict.TryGetValue("key", out var result) ? result : defaultValue;
Best Practices¶
1. Use Appropriate Types¶
// Good: Use decimal for monetary values
runner.SetExternalVariable("premium", 1200.50m);
// Avoid: Using double can cause precision issues
// runner.SetExternalVariable("premium", 1200.50); // Converted to decimal, may lose precision
2. Initialize Environment Once¶
// Good: Initialize once, reuse runner
var constants = new EverDictionary { ["RATE"] = 0.08m };
runner.InitializeEnvironment(constants, new EverDictionary());
for (int i = 0; i < 1000; i++)
{
runner.SetExternalVariable("amount", i * 100);
var result = runner.RunExpression("amount * RATE");
}
// Less efficient: Initialize every time
// for (int i = 0; i < 1000; i++)
// {
// var vars = new EverDictionary { ["amount"] = i * 100 };
// runner.InitializeEnvironment(new EverDictionary(), vars);
// var result = runner.RunExpression("amount * RATE");
// }
3. Check for Null¶
runner.Run("optional = null;");
var value = runner.GlobalVariables["optional"];
if (value == null)
{
Console.WriteLine("Value is null");
}
4. Type Safety¶
// Good: Safe conversion with error handling
try
{
var amount = Convert.ToDecimal(runner.GlobalVariables["amount"]);
}
catch (InvalidCastException)
{
Console.WriteLine("Invalid type for amount");
}
// Or check type first
var value = runner.GlobalVariables["amount"];
if (value is decimal decimalValue)
{
// Use decimalValue
}
See Also¶
- EverSharpRunner API - Complete API reference
- Extension Functions - Creating custom functions
- Data Types - EverSharp type system