Skip to content

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

void InitializeEnvironment(EverDictionary constants, EverDictionary variables)

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