DollarSignEngine 1.2.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package DollarSignEngine --version 1.2.0
                    
NuGet\Install-Package DollarSignEngine -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DollarSignEngine" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DollarSignEngine" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="DollarSignEngine" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DollarSignEngine --version 1.2.0
                    
#r "nuget: DollarSignEngine, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=DollarSignEngine&version=1.2.0
                    
Install DollarSignEngine as a Cake Addin
#tool nuget:?package=DollarSignEngine&version=1.2.0
                    
Install DollarSignEngine as a Cake Tool

DollarSignEngine

Dynamically evaluate and interpolate C# expressions at runtime with ease, leveraging a powerful expression evaluation engine.

Introduction

The DollarSignEngine is a robust C# library designed to simplify the process of dynamically evaluating and interpolating expressions at runtime. Ideal for applications requiring on-the-fly evaluation of string templates, it offers developers the flexibility to inject variables and execute complex C# expressions with the same syntax as C# string interpolation.

Guiding Principles

  1. Core Purpose: Enable runtime evaluation of C# string interpolation ($"{}") exactly as it works in compile-time C#.

  2. Extension Rules:

    • All features natively supported in C# string interpolation must be maintained
    • Avoid extending functionality beyond standard C# interpolation syntax
    • Only add features essential for runtime evaluation
  3. Contributor Guidelines: This library's sole purpose is runtime evaluation of C# interpolation strings. Additional features should only be considered if they directly support this core purpose.

Features

  • Dynamic Expression Evaluation: Evaluate C# expressions dynamically at runtime, with support for interpolation and complex logic.
  • Flexible Parameter Injection: Easily pass parameters into expressions using dictionaries, anonymous objects, or regular C# objects.
  • Support for Complex Types: Effortlessly handle complex data types, including custom objects, collections, and more.
  • Method Invocation: Call methods on parameter objects within expressions, such as {obj.Method()} or ${obj.Method()}, consistent with C# interpolation syntax.
  • Format Specifiers & Alignment: Full support for C# format specifiers and alignment in interpolated expressions.
  • Custom Variable Resolution: Provide custom variable resolvers for advanced use cases.
  • Multiple Syntax Options: Support for both standard C# interpolation {expression} and dollar-sign ${expression} syntax.
  • Comprehensive Error Handling: Provides detailed exceptions for compilation and runtime errors to ease debugging.
  • Powerful Expression Evaluation: Uses DynamicExpresso internally to support a full range of C# expressions including ternary operators, arithmetic operations, and LINQ expressions.

Installation

The library is available on NuGet. You can install it using the following command:

dotnet add package DollarSignEngine

Usage

Below are some examples of how to use the DollarSignEngine to evaluate expressions dynamically.

Basic Interpolation

// Simple interpolation with current date
var result = await DollarSign.EvalAsync("Today is {DateTime.Now:yyyy-MM-dd}");
Console.WriteLine(result); // Outputs: Today is 2023-05-01 (based on current date)

// With parameters using anonymous object
var name = "John";
var result = await DollarSign.EvalAsync("Hello, {name}!", new { name });
Console.WriteLine(result); // Outputs: Hello, John!

// With parameters using dictionary
var parameters = new Dictionary<string, object?> { { "name", "John" } };
var result = await DollarSign.EvalAsync("Hello, {name}!", parameters);
Console.WriteLine(result); // Outputs: Hello, John!

Using Custom Objects

// Using a class directly
public class User
{
    public string Username { get; set; } = string.Empty;
    public int Age { get; set; }
}

var user = new User { Username = "Alice", Age = 30 };
var result = await DollarSign.EvalAsync("User: {Username}, Age: {Age}", user);
Console.WriteLine(result); // Outputs: User: Alice, Age: 30

// Using anonymous types with nested properties
var person = new { 
    Name = "Jane", 
    Address = new { City = "New York", Country = "USA" } 
};
var result = await DollarSign.EvalAsync("Person: {Name} from {Address.City}", person);
Console.WriteLine(result); // Outputs: Person: Jane from New York

// Calling a method on a custom object
public class Greeter
{
    public string Name { get; set; } = string.Empty;

    public string Hello()
    {
        return $"hello, {Name}";
    }
}

var greeter = new Greeter { Name = "Bob" };
var options = new DollarSignOption { SupportDollarSignSyntax = true };
var result = await DollarSign.EvalAsync("Greeting: ${Hello()}", greeter, options);
Console.WriteLine(result); // Outputs: Greeting: hello, Bob

// Without dollar sign syntax, the expression is treated as literal
var standardResult = await DollarSign.EvalAsync("Greeting: ${Hello()}", greeter);
Console.WriteLine(standardResult); // Outputs: Greeting: ${Hello()}

Format Specifiers and Alignment

// Using format specifiers
var price = 123.456;
var result = await DollarSign.EvalAsync("Price: {price:C2}", new { price });
Console.WriteLine(result); // Outputs: Price: $123.46

// Using alignment
var number = 42;
var result = await DollarSign.EvalAsync("Left aligned: {number,-10} | Right aligned: {number,10}", new { number });
Console.WriteLine(result); // Outputs: Left aligned: 42         | Right aligned:         42

// Combined alignment and format
var percentage = 0.8654;
var result = await DollarSign.EvalAsync("Progress: {percentage,8:P1}", new { percentage });
Console.WriteLine(result); // Outputs: Progress:    86.5%

Conditional Logic

// Simple ternary operation
var age = 20;
var result = await DollarSign.EvalAsync("You are {(age >= 18 ? \"adult\" : \"minor\")}.", new { age });
Console.WriteLine(result); // Outputs: You are adult.

// Nested ternary operations
var score = 85;
var result = await DollarSign.EvalAsync("Grade: {(score >= 90 ? \"A\" : score >= 80 ? \"B\" : \"C\")}.", new { score });
Console.WriteLine(result); // Outputs: Grade: B.

// Complex condition with formatting
var price = 123.456;
var discount = true;
var result = await DollarSign.EvalAsync("Final price: {(discount ? price * 0.9 : price):C2}", 
    new { price, discount });
Console.WriteLine(result); // Outputs: Final price: $111.11

Working with Collections

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var result = await DollarSign.EvalAsync("Total sum: {numbers.Sum()}. Items count: {numbers.Count}", new { numbers });
Console.WriteLine(result); // Outputs: Total sum: 15. Items count: 5

var settings = new Dictionary<string, string> { { "Theme", "Dark" }, { "FontSize", "12" } };
var result = await DollarSign.EvalAsync("Theme: {settings[\"Theme\"]}, Font Size: {settings[\"FontSize\"]}", new { settings });
Console.WriteLine(result); // Outputs: Theme: Dark, Font Size: 12

Dollar Sign Syntax

// When working with text that contains literal curly braces (like JSON),
// enable dollar sign syntax to specify which parts should be interpolated
var options = new DollarSignOption { SupportDollarSignSyntax = true };

var user = new { name = "Alice", age = 30 };

// With dollar sign syntax enabled, only ${...} is interpolated
var jsonTemplate = "{ \"user\": { \"name\": \"{name}\", \"age\": ${age} } }";
var result = await DollarSign.EvalAsync(jsonTemplate, user, options);
Console.WriteLine(result); 
// Outputs: { "user": { "name": "{name}", "age": 30 } }

// In standard mode (default), all {...} expressions are interpolated
var standardResult = await DollarSign.EvalAsync("{ \"user\": { \"name\": \"{name}\", \"age\": {age} } }", user);
Console.WriteLine(standardResult); 
// Outputs: { "user": { "name": "Alice", "age": 30 } }

// Example with method invocation
var greeter = new Greeter { Name = "Bob" };
var methodResult = await DollarSign.EvalAsync("Greeting: ${greeter.Hello()}", new { greeter }, options);
Console.WriteLine(methodResult); // Outputs: Greeting: hello, Bob

Arithmetic and LINQ Operations

// Arithmetic operations
var values = new { a = 10, b = 5 };
var result = await DollarSign.EvalAsync("Sum: {a + b}, Product: {a * b}, Division: {a / b}", values);
Console.WriteLine(result); // Outputs: Sum: 15, Product: 50, Division: 2

// LINQ operations with collections
var items = new { products = new[] { 
    new { Name = "Apple", Price = 1.99 }, 
    new { Name = "Orange", Price = 0.99 }, 
    new { Name = "Banana", Price = 0.59 } 
}};
var result = await DollarSign.EvalAsync(
    "Average price: {products.Average(p => p.Price):C2}, Most expensive: {products.OrderByDescending(p => p.Price).First().Name}",
    items);
Console.WriteLine(result); // Outputs: Average price: $1.19, Most expensive: Apple

Custom Variable Resolution

// Create a custom variable resolver
var options = new DollarSignOption
{
    VariableResolver = (expression, parameter) =>
    {
        // Custom logic to resolve variables
        if (expression == "currentUser")
            return "Admin";
        
        // Return null to fall back to standard resolution
        return null;
    }
};

var result = await DollarSign.EvalAsync("Current user: {currentUser}", null, options);
Console.WriteLine(result); // Outputs: Current user: Admin

Configuration Options

The DollarSignOption class provides several options to customize the behavior of the expression evaluation:

var options = new DollarSignOption
{
    // Whether to throw an exception when a parameter is missing
    ThrowOnMissingParameter = false,
    
    // Whether to enable debug logging
    EnableDebugLogging = false,
    
    // Additional namespaces to import in the script
    AdditionalNamespaces = new List<string> { "System.Text.Json" },
    
    // Whether to use strict mode for parameter access
    StrictParameterAccess = false,
    
    // The culture to use for formatting operations
    CultureInfo = new CultureInfo("en-US"),
    
    // Whether to support dollar sign prefixed variables (${name})
    SupportDollarSignSyntax = true,
    
    // A callback for custom variable resolution
    VariableResolver = (expression, parameter) => { /* ... */ },
    
    // Whether to optimize ternary operator evaluation
    OptimizeTernaryEvaluation = true
};

Error Handling

The library provides the DollarSignEngineException for handling errors during expression evaluation:

try
{
    var result = await DollarSign.EvalAsync("Value: {nonExistentVariable}", null, 
        new DollarSignOption { ThrowOnMissingParameter = true });
}
catch (DollarSignEngineException ex)
{
    Console.WriteLine($"Error: {ex.Message}");
    // Handle the error...
}

Implementation Details

DollarSignEngine uses DynamicExpresso internally for expression evaluation. This provides robust support for a wide range of C# expressions, including:

  • Arithmetic operations
  • Ternary operators
  • Method calls
  • LINQ queries
  • Property access
  • Collection indexing

The library handles parsing templates, extracting expressions, evaluating them using DynamicExpresso, and applying format specifiers before assembling the final output.

Performance Considerations

  • Expression evaluation results are cached when possible to improve performance for repeated calls
  • Avoid unnecessary complex expressions in performance-critical code paths
  • For templates that are evaluated many times with different parameters, consider reusing the same template string
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on DollarSignEngine:

Package Downloads
DocuChef

A flexible .NET library that transforms data into professionally formatted documents through intuitive template binding, serving Excel, Word, PowerPoint, and beyond.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.3.4 30 6/1/2025
1.3.3 107 5/29/2025
1.3.2 109 5/29/2025
1.3.1 53 5/24/2025
1.3.0 128 5/22/2025
1.2.0 216 5/15/2025
1.1.0 138 5/1/2025
1.0.3 138 6/4/2024
1.0.2 161 4/4/2024
1.0.1 118 4/4/2024