Home

Awesome

Actions Status

Licensing

This is a paid package, you can use it anywhere if you purchased it.

Introduction

This package provides the API for parsing and expression execution written in C#. It is specially designed to work with the Unity on various platforms. Since it is written in C# 3.5 and has no additional dependencies, it should work with any version of Unity (and .NET framework).

It is tested to work on:

It should work on any other platforms.

:warning: For AOT execution platforms (iOS, WebGL, IL2CPP) a link.xml should be added to project's root directory. Read more about IL code stripping in official documentation.

API

Example

Parsing C# expression into System.Linq.Expression.Expression[T]:

var mathExpr = "Math.Max(x, y)";
var exprTree = CSharpExpression.Parse<double, double, double>(mathExpr, arg1Name: "x", arg2Name: "y") 
// exprTree -> Expression<Func<double, double, double>>

Evaluating C# expression:

var arifExpr = "2 * (2 + 3) << 1 + 1 & 7 | 25 ^ 10";
var result = CSharpExpression.Evaluate<int>(arifExpr); 
// result -> 19

Parser

The parser recognizes the C# 4 grammar only. It includes:

Nullable types are supported. Generics are supported. Enumerations are supported. Type inference is not available and your should always specify generic parameters on types and methods.

Known Types

For security reasons the parser does not provide access to any types except:

To access other types your should pass typeResolver parameter in Parse and Evaluate method:

var typeResolver = new KnownTypeResolver(typeof(Mathf), typeof(Time));
CSharpExpression.Evaluate<int>("Mathf.Clamp(Time.time, 1.0f, 3.0f)", typeResolver); 

If you want to access all types in UnityEngine you can pass custom AssemblyTypeResolver as typeResolver parameter.

var typeResolver = new AssemblyTypeResolver(typeof(UnityEngine.Application).Assembly);

ℹ️ For security reasons any method/property calls on System.Type will throw exceptions until System.Type is added as known type.

AOT Execution

You can compile and evaluate expression created by System.Linq.Expression and execute it in AOT environment where it is usually impossible.

var expr = (Expression<Func<Vector3>>)(() => new Vector3(1.0f, 1.0f, 1.0f));
var fn = expr.CompileAot();

fn; // -> Func<Vector3>
fn(); // -> Vector3(1.0f, 1.0f, 1.0f)

iOS, WebGL and most console platforms use AOT compilation which imposes following restrictions on the dynamic code execution:

See Also

WebGL and iOS

You can prepare Func<> lambda for AOT compilation/execution by registering it with AotCompilation.RegisterFunc.

AotCompilation.RegisterFunc<int, bool>(); // will enable Func<int, bool> lambdas anywhere in expressions

Unity 2020.3.2 Issues

This version of Unity has runtime bug related to lambda compilation. Please use following workaround for IL2CPP/AOT runtime:

#if ((UNITY_WEBGL || UNITY_IOS || ENABLE_IL2CPP) && !UNITY_EDITOR)
GameDevWare.Dynamic.Expressions.AotCompilation.IsAotRuntime = true;
#endif

Improving Performance

You can improve the performance of methods invocation by registering their signatures in AotCompilation.RegisterForFastCall().

// Supports up to 3 arguments.
// First generic argument is your class type.
// Last generic argument is return type.

AotCompilation.RegisterForFastCall<InstanceT, ResultT>()
AotCompilation.RegisterForFastCall<InstanceT, Arg1T, ResultT>()
AotCompilation.RegisterForFastCall<InstanceT, Arg1T, Arg2T, ResultT>()
AotCompilation.RegisterForFastCall<InstanceT, Arg1T, Arg2T, Arg3T, ResultT>()

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>();

Roadmap

You can send suggestions at support@gamedevware.com

Changes

2.3.0

2.2.9

2.2.8

2.2.7

2.2.6

2.2.5

2.2.4

2.2.3

2.2.2

2.2.1

2.2.0

Features

2.1.4

2.1.2-rc

Features

CSharpExpression.Evaluate<int?>("default(int?)"); // -> null
CSharpExpression.Evaluate<int, int, int>("(x,y) => x + y", 2, 2); // -> 4
public Binder(Type lambdaType, ITypeResolver typeResolver = null);
CSharpExpression.Evaluate<int>("int.MaxValue");

Bugs

Breaking changes in 2.0

1.0.1.11

CSharpExpression.Evaluate<int>("2 ** 2"); // -> 4

1.0.1.10

1.0.1.9

Installation

Nuget:

Install-Package GameDevWare.Dynamic.Expressions

Unity:

Package at Unity Asset Store

Contacts

Please send any questions at support@gamedevware.com

License

Asset Store Terms of Service and EULA