C# Expression Trees!
Have you ever wondered how a property of an object can be passed to a method? I mean the property itself, not its value! Why does it matter to be able to pass a property, you might ask. Let me explain with an example. Let’s say we want to write a method that accepts a string property of an object and prints the name of the property followed by its value. How should this method be written? For the sake of demonstration, let’s suppose that we have a Person class that has two string properties, FirstName and LastName. personInstance is an instance of this class.
public Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
//... inside the main method
Person personInstance = new Person
{
FirstName = "John",
LastName = "Doe"
};
The goal here is to write a method PrintProperty in a way that if a property of an
object is passed to it, it will print the name and the value of the property. For instance, if
the method is called this way, PrintProperty(FirstName property of personInstance)
,
it will print “FirstName: John”. Now the question is, how can we define this
PrintProperty method? How can we pass the property to it?
First, let’s talk a bit about properties. In order for a property to be accessed at runtime, we need the property name and an object that has that property. Once we have this information, we can find the value of the property with help of reflection. So, the problem is now reduced to finding a way to pass an object and a property name to a method. In this post, I am going to explain three different approaches to address this problem.
Approach #1: The naive approach
We can simply pass the object and property name, and the rest can be handled by reflection.
static void PrintProperty1(object obj, string propertyName)
{
var property = obj.GetType().GetProperty(propertyName);
Console.WriteLine($"{propertyName}: {property.GetValue(obj)}");
}
// ... inside the main method
PrintProperty1(personInstance, "FirstName");
Here, we are using a string to identify the property. But what if at some point we decide to change the name of the property to Name instead of FirstName? Or what prevents me from passing “InvalidProperty” as the property name? There’s no way to ensure propertyName is a property of obj at compile-time.
Approach #2: Using nameof expression
Before C# 6.0, there was no good way to obtain the name of a property programmatically. But C# 6.0 introduced nameof expression that is helpful in this situation.
static void PrintProperty2(object obj, string propertyName)
{
var property = obj.GetType().GetProperty(propertyName);
Console.WriteLine($"{propertyName}: {property.GetValue(obj)}");
}
// ... inside the main method
PrintProperty2(personInstance, nameof(personInstance.FirstName));
As you can see, the body of PrintProperty2 is the same as PrintProperty1, what has changed, is how we pass the property name to it. Using nameof expression, if we change name of the property to Name at some point, it won’t compile. But since the parameter is string, I’m not forced to use nameof and still nothing prevents me from passing “InvalidProperty” as the property name. This approach is OK but doesn’t look cool to me. Since what we are trying to achieve, is to pass the FirstName property to the method, wouldn’t it be better if we could simply pass personInstance.FirstName? Well, the answer is we can, somehow! Expression trees are here to help! Before moving on to the third approach, let’s talk about expression trees a bit.
You can be a C#/.net developer for years and have never heard of expression trees. Before
explaining expression trees, I am going to ask you a simple question to test your knowledge of
expression trees. Let’s assume that we’re going to assign the following lambda expression to a
variable named x. obj is an object of a class that has an int property named
prop. What kinds of possible types can replace var
keyword below?
var x = () => obj.prop;
If your answer to this question does not include Expression<Func<int>>
, you
are probably ignorant of expression trees!
Normally, when you assign an expression, a+b
for instance, to a variable
x, the expression is computed and its value is assigned to x. So, after it is
assigned, x only knows the computed value and has no idea how the value is computed,
therefore if you change the value of a, the value of x won’t change. It’s not
the same for lambda expressions. If you assign a lambda expression, let’s say () => a + b
, to a variable
f, the value a+b
is not
computed at first. In contrast to the previous case, where the value got computed and stored in
x, here, the instruction to produce the value is stored in f. Strictly
speaking, f captures variables a and b and every time it gets
invoked, it adds these two variables and returns the value. With the help of expression trees,
you can create and manipulate these instructions.
Cool as it may sound, it seems hard to find a real-world situation in which expression trees can
come in handy. You might be surprised by the fact that how expression trees are being used in
LINQ to Sql. For instance, Where
extension method that is applied to IEnumerable<T>
and Where
extension method that is used for
IQueryable<T>
, although look
similar in usage and name, accept different type of parameters. Former expects a Func<T, bool>
as the first
parameter while the latter expects a Expression<Func<T, bool>>
.
You can learn more about this usage here.
Now, let’s see how expression trees can help us solve our main problem!
Approach #3: Expression Trees!
As I mentioned above, we can just pass personInstance.FirstName
to the method.
But if we do so, what the method will get is the value of personInstance.FirstName
which is string
“John”. So, we can instead pass () => personInstance.FirstName
as an
expression to the method and analyse it to find the object and its property member.
() => personInstance.FirstName
as an
Expression, is a LambdaExpression
, it
has a Body property that defines what the lambda expression will return. The
Body property in this case is a MemberExpression
- since we are trying
to access a member of another expression using the dot operator. The member expression itself
has an Expression property, which defines the expression that we are trying to access
its member and a Member property. Member property of the MemberExpression
is a MemberInfo
object that has a
Name property, which in this case is “FirstName”. There is an implicit level of member
accessing here. Since personInstance is defined inside the main method, it
cannot be accessed elsewhere, hence, the lambda expression will capture the
personInstance object and store it inside a compiler-generated class as a field named
personInstance. So personInstance object is a property inside an implicit
compiler-generated class. As a result Expression property of the member expression, in
this case, is also a MemberExpression
with its Member property being a MemberInfo
with personInstance
name and its Expression being a ConstantExpression
that has that
compiler-generated class as its value. Following diagram demonstrates how the expression tree of
this simple lambda expression will look like.
Expression tree of
() => personInstance.FirstName
(the diagram is made using draw.io)
Now we can use the above information to implement PrintProperty3 method.
static void PrintProperty3(Expression<Func<string>> propertyExpression)
{
var memberExpression = propertyExpression.Body as MemberExpression;
var implicitMemberExpression = memberExpression.Expression as MemberExpression;
var objectName = implicitMemberExpression.Member.Name;
var constantExpression = implicitMemberExpression.Expression as ConstantExpression;
var owner = constantExpression.Value;
var obj = owner.GetType().GetField(objectName).GetValue(owner);
var property = memberExpression.Member as PropertyInfo;
Console.WriteLine($"{property.Name}: {property.GetValue(obj)}");
}
// ... inside the main method
PrintProperty3(() => personInstance.FirstName);
In this approach, the method body is longer compared to the ones in previous approaches. However,
when it comes to using it, passing the property is more straightforward. We can feel that we’re
actually passing a property. In this case if we decide to rename FirstName property to
Name we will get a compilation error. This approach is not completely safe though, we can pass
() => “Hello”
as the parameter! But
at least we’re not relying on strings to specify properties. I personally prefer not to use
nameof expression unless there is no better choice.
We just learned a new technique to specify properties. In the next part I’ll explain how this technique can be used in WPF/Xamarin.Forms applications. If you don’t know or care about WPF or Xamarin.Forms you can skip this part.
Applications in WPF/Xamarin.Forms
XAML-based technologies in C# like WPF or Xamarin.Forms, provide an ICommand
interface to implement command
design pattern. It is common among developers to use a single DelegateCommand -or
RelayCommand– class to create new commands instead of creating a new class and
implementing ICommand
for each new
command. Let’s assume that you have a sign up form. There is a “I Agree to the Terms” checkbox
that is bound to a bool property named Agreed in your view model. There is also a button that
must be disabled if the checkbox is not checked. You create your command inside your view model
this way:
// define SubmitCommand property inside the view model
DelegateCommand SubmitCommand { get; set; }
// ... inside the constructor
this.SubmitCommand = new DelegateCommand(this.Submit(), () => this.Agreed);
Obviously, the submit button on your form must be bound to SubmitCommand property. This
way, even if you check the checkbox, you’ll notice that the button won’t be enabled. That’s
because the button won’t automatically check your CanExecute command to see if it’s changed. If
your CanExecute function depends on some of the properties in your view model, you should fire
CanExecute event of DelegateCommand manually every time one of these properties is changed. It’s
fine to add this.SubmitCommand.RaiseCanExecuteChanged()
to the getter of Agreed property. But suppose that you have many commands that depend
on Agreed property and also your SubmitCommand depends on some other
properties. You’ll end up with ugly getters, and it would become a headache to manage their
relations. However, you can take advantage of INotifyPropertyChanged
interface and use
the technique explained above to tell your commands to observe the properties. You can implement
a method in your DelegateCommand class to watch for property changes. And then you can simply
initialize your SubmitCommand this way:
this.SubmitCommand = new DelegateCommand(this.Submit(), () => this.Agreed);
this.SubmitCommand.ObservesProperty(() => this.Agreed);
And you’re done.
As a bonus, the Prism library has a nice implementation of DelegateCommand class with an ObservesProperty method. You can check it out on their github.