GameDevWare.Dynamic.Expressions
3.0.0
dotnet add package GameDevWare.Dynamic.Expressions --version 3.0.0
NuGet\Install-Package GameDevWare.Dynamic.Expressions -Version 3.0.0
<PackageReference Include="GameDevWare.Dynamic.Expressions" Version="3.0.0" />
<PackageVersion Include="GameDevWare.Dynamic.Expressions" Version="3.0.0" />
<PackageReference Include="GameDevWare.Dynamic.Expressions" />
paket add GameDevWare.Dynamic.Expressions --version 3.0.0
#r "nuget: GameDevWare.Dynamic.Expressions, 3.0.0"
#:package GameDevWare.Dynamic.Expressions@3.0.0
#addin nuget:?package=GameDevWare.Dynamic.Expressions&version=3.0.0
#tool nuget:?package=GameDevWare.Dynamic.Expressions&version=3.0.0
Licensing
This package is available for purchase on the Unity Asset Store. A valid license is required for use in any project.
Overview
This package delivers a C# parsing and expression execution API designed for Unity compatibility across multiple platforms. Implemented in C# 3.5 with no external dependencies, it maintains broad compatibility with Unity versions and .NET frameworks.
Verified Platform Support
• iOS
• Android
• WebGL
• Windows/macOS/Linux
The solution should function on additional Unity-supported platforms.
Important Note for AOT Platforms (iOS, WebGL, IL2CPP):
Projects targeting AOT compilation require inclusion of a link.xml file in the project root directory. Refer to Unity's documentation on IL code stripping for additional context.
Core API
• CSharpExpression
- Evaluate
- Parse
• AotCompilation - RegisterFunc
- RegisterForFastCall (performance optimization)
Implementation Examples
Expression Parsing:
var mathExpr = "Math.Max(x, y)";
var exprTree = CSharpExpression.Parse<double, double, double>(mathExpr, arg1Name: "x", arg2Name: "y");
// Returns Expression<Func<double, double, double>>
var expr = exprTree.CompileAot();
// Returns Func<double, double, double>
Expression Evaluation:
var arifExpr = "2 * (2 + 3) << 1 + 1 & 7 | 25 ^ 10";
var result = CSharpExpression.Evaluate<int>(arifExpr);
// Returns 19
Parser Specifications
The parser implements C# 4 grammar with support for:
• Arithmetic, bitwise, and logical operations
• Conditional and null-coalescing operators
• Method/delegate/constructor invocation
• Property/field access and indexers
• Type operations (casting, conversion, is/as/typeof/default)
• Expression grouping and checked/unchecked contexts
• Type aliases and null-conditional operators
• Power operator (**)
• Lambda expressions
• Literal values (true, false, null)
Type Support:
• Nullable types
• Generics
• Enumerations
Note: Type inference is not implemented - explicit generic parameter specification is required.
Type Resolution
For security, the parser restricts type access to:
• Argument types
• Primitive types
• Math, Array, and Func<> types
Additional types require specification through the typeResolver parameter:
var typeResolver = new KnownTypeResolver(typeof(Mathf), typeof(Time));
CSharpExpression.Evaluate<int>("Mathf.Clamp(Time.time, 1.0f, 3.0f)", typeResolver);
Full namespace access can be enabled via AssemblyTypeResolver:
var typeResolver = new AssemblyTypeResolver(typeof(UnityEngine.Application).Assembly);
Security Note: System.Type operations will throw exceptions unless System.Type explicitly added as a known type.
AOT Compilation Support
The package enables compilation and execution of System.Linq.Expression expressions in AOT environments:
var expr = (Expression<Func<Vector3>>)(() => new Vector3(1.0f, 1.0f, 1.0f));
var fn = expr.CompileAot();
// Returns Func<Vector3>
AOT Environment Requirements (iOS, WebGL and most console platforms):
- Only Expression<Func<...>> delegate types supported
- Only static methods using primitives arguments receive optimization
- All referenced members must be visible to Unity's static analyzer to prevent eager IL code stripping
- ⚠️ Required link.xml configuration (see above)
See Also
Platform-Specific Considerations
WebGL and iOS:
• Func<> lambdas limited to 4 arguments
• Instance methods incur reflection overhead
• Value types experience moderate boxing
Preparation for AOT Execution:
AotCompilation.RegisterFunc<int, bool>(); // Enables Func<int, bool> in expressions
Unity 2020.3.2 Workaround:
#if ((UNITY_WEBGL || UNITY_IOS || ENABLE_IL2CPP) && !UNITY_EDITOR
GameDevWare.Dynamic.Expressions.AotCompilation.IsAotRuntime = true;
#endif
Performance Optimization
Method invocation performance can be enhanced through signature registration:
// Supports up to 3 arguments
AotCompilation.RegisterForFastCall<MyClass, ReturnType>();
AotCompilation.RegisterForFastCall<MyClass, Arg1Type, ReturnType>();
// Additional signatures...
Example:
public class MyVectorMath
{
public Vector4 Dot(Vector4 vector, Vector4 vector);
public Vector4 Cross(Vector4 vector, Vector4 vector);
public Vector4 Scale(Vector4 vector, float scale);
}
// register Dot and Cross method signatures
AotCompilation.RegisterForFastCall<MyVectorMath, Vector4, Vector4, Vector4>();
// register Scale method signature
AotCompilation.RegisterForFastCall<MyVectorMath, Vector4, float, Vector4>();
Development Roadmap
• Expression serialization (completed)
• Void expression support (completed)
• Future enhancements:
- Delegate construction from method references
- Generic type inference
- C#6 syntax support
- Extension method support
- Type/list initializers
Feature suggestions may be submitted to support@gamedevware.com.
Roadmap
You can send suggestions at support@gamedevware.com
- ~Expression serialization~
- ~Void expressions (
System.Actiondelegates)~ - Parser: Delegate construction from method reference
- Parser: Type inference for generics
- Parser: Full C#6 expression syntax
- Parser: Extension methods
- Parser: Type initializers, List initializers
Changes
2.3.0
- fix: fixed netcore related error with enumerable.empty<T>
- feature: added optional
globalparameter to all CSharpExpression methods to allow specify global object for expression. - test: removed flaky test with double.tostring() comparison
- fix: fixed typo in
arg4NameinCSharpExpression.ParseFunc{4}andCSharpExpression.ParseAction{4}
2.2.9
- fix: fixed error with instantiated generic method on types (which is impossible in normal conditions, but fine for Unity AOT runtime).
2.2.8
- feature:made AotCompilation.IsAotRuntime is mutable, this will allow to signal for AOT runtime and suppress further checks.
2.2.7
- feature: added public CSharpExpression.Format method for SyntaxTreeNode
2.2.6
- changed order or SyntaxTreeNode fields and added "original C# expression" field to parsed AST.
- refactored C# expression rendering to support null-propagation expressions, type aliases (int, byte, object ...),
- renamed "Render" methods to "FormatAsCSharp". Now it is "formatting"
- moved c# "formatting" methods to CSharpExpression class
- mark old "Parse" functions as errors
- mark old "Render" methods as obsolete
- renamed CSharpExpressionFormatter to CSharpExpressionFormatter
- fixed indexer experssion rendering
- refactored NameUtils to properly render C# type names
2.2.5
- renamed ParseTreeNode.Lexeme to .Token
- renamed few member of TokenType for better clarity
- added documentation file in Unity project assets
- changed 'propertyOrFieldName' attribute to 'name' in SyntaxTreeNode
- renamed PropertyOfFieldBinder to MemberBinder
- changed 'PropertyOrField' expression type to 'MemberResolve' in SyntaxTreeNode
- added backward compatibility checks in all related classes
2.2.4
- added protection against wrong expressions like 'a b' which later bound as 'b'
- fixed some tokenization errors:
-
- 'issa'scanned as 'is'[Operator] and 'sa'[Identifier], now as 'issa'
-
- '.09' scanned as '.'[Operator] and '09'[Number], now as '0.09'
-
- '0.1x' scanned as '0.1'[Number] and 'x'[Identifier], now cause error
- added method calls on numbers (example 1.ToString())
- added short number notation (example '.9' for '0.9')
- added '@' prefix for identifiers (example '@is') https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/verbatim
- done small Tokenizer optimization (reduced string allocation during scanning)
2.2.3
- added ExpressionPacker type. This type allows packing/unpacking expressions into primitive structures (Dictionaries, Arrays...). These structures could be serialized and wired by network or stored for future use.
- added better error message for some binding cases
- denying call to 'Type.InvokeMember' if 'Type' is not within 'known types'.
2.2.2
- fixed conditional operator (a ? b : c) parsing with method call in place of 'b'
2.2.1
- fixed IL2CPP compilation error due _Attribute interface complilation failure
- added few interfaces to AOT.cs file for better AOT coverage
2.2.0
Features
- added support for void expressions (Action<> delegates)
- added support of '.NET Standart 1.3' and '.NET Core 2.0' platforms
2.1.4
- Release version, no actual changes except readme.md
2.1.2-rc
Features
- added more descriptive message for member binding error
- added autodoc comments for public members
- hid
ReadOnlyDictionaryfrom public access - removed Unity WebGL #if for unsigned types. Unity's bug was fixed.
- added support for generic types and generic methods
- added nullable types and
?suffix support
CSharpExpression.Evaluate<int?>("default(int?)"); // -> null
- added lambda expressions. Syntax is
() => xandnew Func(a => x) - added support for expression's parameter re-mapping with lambda expression syntax:
CSharpExpression.Evaluate<int, int, int>("(x,y) => x + y", 2, 2); // -> 4
- added support for
Func<>lambdas for AOT environments - added additional constructor to Binder class
public Binder(Type lambdaType, ITypeResolver typeResolver = null);
- added
ArgumentsTree.ToString()method - added aliases for build-in types. Aliases resolved during binding phase inside
Binder.Bind()method.
CSharpExpression.Evaluate<int>("int.MaxValue");
Bugs
- fixed error with wrongly resolved types (only by name) in KnownTypeResolver
- fixed bug with ACCESS_VIOLATION on iOS (Unity 5.x.x IL2CPP)
- fixed few Unity 3.4 related errors in code
- fixed 'new' expression parsed with error on chained calls new a().b().c()
- fixed some cases of lifted binary/unary/conversion operations
- fixed some AOT'ed operations on System.Boolean type
- fixed null-propagation chains generate invalid code
- fixed some edge cases of resolving nested generic types
- fixed error with types without type.FullName value
- fixed Condition operator types promotion
- fixed Power operator types promotion and null-lifting
- fixed enum constants threated as underlying types during binary/unary operations
Breaking changes in 2.0
- ParserNode renamed to ParseTreeNode
- ExpressionTree renamed to SyntaxTreeNode
- ExpressionBuilder renamed to Binder
- ITypeResolutionService renamed to ITypeResolver
- ITypeResolver.GetType removed
- ITypeResolver now could be configured with TypeDiscoveryOptions
1.0.1.11
- fixed error them creating nullable types via "new" keyword
- fixed Embedded Resource addressing problem on IL2CPP WebGL (localized error messages)
- fixed some cases of nullable types binding
- fixed Enum member resolution
- added Power(
**) operator into C# syntax
CSharpExpression.Evaluate<int>("2 ** 2"); // -> 4
- added TypeResolutionService chaining for better KnownTypes re-use
1.0.1.10
- fixed error with nulled constants after first call for AOT-ted expression.
- added ToString() impl for ExpressionTree
1.0.1.9
- added Null-conditional Operators (example: a.?b.?.c)
- fixed array indexing expressions
- added array types support in type expressions ('convert', 'typeof', 'is' etc.)
Installation
Install-Package GameDevWare.Dynamic.Expressions
Unity:
Contacts
Please send any questions at support@gamedevware.com
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. 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 is compatible. 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 | netcoreapp1.0 was computed. netcoreapp1.1 was computed. netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 is compatible. |
| .NET Standard | netstandard1.6 is compatible. netstandard2.0 was computed. netstandard2.1 is compatible. |
| .NET Framework | net45 is compatible. net451 was computed. net452 was computed. net46 was computed. net461 is compatible. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 is compatible. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen30 was computed. tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETCoreApp 3.1
- No dependencies.
-
.NETFramework 4.5
- No dependencies.
-
.NETFramework 4.6.1
- No dependencies.
-
.NETFramework 4.8
- No dependencies.
-
.NETStandard 1.6
- No dependencies.
-
.NETStandard 2.1
- No dependencies.
-
net10.0
- No dependencies.
-
net6.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0 | 0 | 2/3/2026 |
| 2.3.0 | 1,519 | 3/26/2023 |
| 2.2.9 | 659 | 10/10/2022 |
| 2.2.8 | 737 | 2/17/2022 |
| 2.2.7 | 2,119 | 11/29/2020 |
| 2.2.6 | 1,408 | 9/15/2019 |
| 2.2.5 | 1,154 | 4/20/2019 |
| 2.2.4 | 1,227 | 9/3/2018 |
| 2.2.2 | 2,149 | 5/16/2018 |
| 2.2.1 | 2,180 | 12/19/2017 |
| 2.2.0 | 2,224 | 11/30/2017 |
| 2.1.4 | 1,836 | 10/22/2017 |
| 1.0.1.10 | 2,099 | 11/18/2016 |
# 3.0.0
BREAKING CHANGE: Changed the distribution form to Unity Package instead of a library.
feature: Added parser support for object initializers and collections initializers.
fix: fix for Mono failture to return underlying type code for Enum types
chore: Increased C# language support to version 7.3 and formatted the code.
BREAKING CHANGE: Raised the minimum .NET Framework version to 4.6.
chore: Added new compilation targets to support modern .NET versions.
# 2.3.0
fix: fixed netcore related error with enumerable.empty<T>
feature: added optional `global` parameter to all CSharpExpression methods to allow specify global object for expression.
test: removed flaky test with double.tostring() comparison
fix: fixed typo in `arg4Name` in `CSharpExpression.ParseFunc{4}` and `CSharpExpression.ParseAction{4}`
# 2.2.9
fix: fixed error with instantiated generic method on types (which is impossible in normal conditions, but fine for Unity AOT runtime).
# 2.2.8
- made AotCompilation.IsAotRuntime is mutable, this will allow to signal for AOT runtime and suppress further checks.
# 2.2.7
- added public CSharpExpression.Format method for SyntaxTreeNode
# 2.2.6
- changed order or SyntaxTreeNode fields and added "original C# expression" field to parsed AST.
- refactored C# expression rendering to support null-propagation expressions, type aliases (int, byte, object ...),
- renamed "Render" methods to "FormatAsCSharp". Now it is "formatting"
- moved c# "formatting" methods to CSharpExpression class
- mark old "Parse" functions as errors
- mark old "Render" methods as obsolete
- renamed CSharpExpressionFormatter to CSharpExpressionFormatter
- fixed indexer experssion rendering
- refactored NameUtils to properly render C# type names
# 2.2.5
renamed ParseTreeNode.Lexeme to .Token
renamed few member of TokenType for better clarity
added documentation file in Unity project assets
changed 'propertyOrFieldName' attribute to 'name' in SyntaxTreeNode
renamed PropertyOfFieldBinder to MemberBinder
changed 'PropertyOrField' expression type to 'MemberResolve' in SyntaxTreeNode
added backward compatibility checks in all related classes
# 2.2.4
added protection against wrong expressions like 'a b' which later bound as 'b'
fixed some tokenization errors:
- 'issa'scanned as 'is'[Operator] and 'sa'[Identifier], now as 'issa'
- '.09' scanned as '.'[Operator] and '09'[Number], now as '0.09'
- '0.1x' scanned as '0.1'[Number] and 'x'[Identifier], now cause error
added method call support for numbers (example 1.ToString())
added short number notation (examples '.9' for '0.9')
added '@' prefix for identifiers (example '@is') https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/verbatim
done small Tokenizer optimization (reduced string allocation during scanning)
# 2.2.3
added ExpressionPacker type. This type allows packing/unpacking expressions into primitive structures (Dictionaries, Arrays...). These structures could be serialized and wired by network or stored for future use.
added better error message for some binding cases
denying call to 'Type.InvokeMember' if 'Type' is not within 'known types'.
# 2.2.2
* fixed conditional operator (a ? b : c) parsing with method call in place of 'b'
# 2.2.1
* fixed IL2CPP compilation error due _Attribute interface complilation failure
* added few interfaces to AOT.cs file for better AOT coverage
# 2.2.0
Features
* added support for void expressions (Action<> delegates)
* added support of '.NET Standart 1.3' and '.NET Core 2.0' platforms