-
Notifications
You must be signed in to change notification settings - Fork 121
Using an expression owner
An expression can optionally be attached to a class. The class to which the expression is attached to is called the expression owner. Once attached, an expression behaves like an instance method of the owner class and thus has access to all of its static, instance, public and non-public members.
The main advantages of using an expression owner are: You can reference the owner's instance members Accessing fields and properties is faster than using variables You can access private members without the performance hit of reflection The owner class does not have to be public You can change the instance of the owner after an expression is compiled, thus allowing you to change the "context" of an expression An expression with an owner can also access the public members of internal types that are in the same module as the owner
We define a class which we will use as the expression owner:
class ExpressionOwner
{
private int MyField;
public int Func(int i)
{
return i;
}
public void SetFieldValue(int value)
{
MyField = value;
}
public int Property
{
get { return 100; }
}
}
We can now define an expression, pass our class as the owner, and reference its members in the expression:
ExpressionOwner owner = new ExpressionOwner();
ExpressionContext context = new ExpressionContext(owner);
// Allow access to private members
context.Options.OwnerMemberAccess = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic;
// Create an expression and pass in our owner
IDynamicExpression e = context.CompileDynamic("func(myfield + Property) + 100");
object o = e.Evaluate();
// Create another instance of the owner
ExpressionOwner owner2 = new ExpressionOwner();
owner2.SetFieldValue(16);
// Set it on the expression
e.Owner = owner2;
// Re-evaluate
o = e.Evaluate();
Controlling owner member access
By default, an expression will only allow access to the public members of its owner. You can use the ExpressionOptions.OwnerMemberAccess property to grant/deny access to the public and non-public members of the owner.
In case you need more fine-grained control, you can use the ExpressionOwnerMemberAccessAttribute to explicitly set the accessibility of fields, properties, and methods on the owner. The setting in the attribute overrides the setting in the ExpressionOptions. This means that you can deny access to all non-public members but allow access to a specific non-public member by tagging it with the attribute.
For example, the function "Func1" in the following class will never be accessible in an expresssion because the false setting on the attribute will override the setting in the ExpressionOptions:
class ExpressionOwner
{
[ExpressionOwnerMemberAccess(false)]
public int Func1()
{
}
}