Lecture thumbnail 0:00 / 0:00 Property change notifications are really useful when working, particularly working with user interfaces,

but there are problems with them.

One of those problems is dependencies between the different properties.

Now this problem is huge.

It’s a very complicated problem and it doesn’t have any easy solutions, but we’re going to try and

tackle it anyway.

We’ll tackle some of the issues related to property dependencies.

I don’t promise a complete and full solution because it would just be too big.

But let me show you first of all, where the problem actually is.

So imagine you have a class called person, so you’ve got a person that person might have an age.

Now, in addition, the person may or may not be able to vote.

So we can have a getter, a Boolean getter called can Vote, which checks that the age is greater than

or equal to 16.

Let’s suppose you can vote from 16 onwards.

So this class at the moment is okay, but when you add change notifications, then it becomes a bit

broken.

So let’s do that in PC.

So I’m going to implement, I notify property change.

Let me once again do a bit of housekeeping here to get the layout’s nice.

Now what I’m going to do is I’m going to modify age to support change notification and something different

is going to happen compared to what you’ve seen before.

So when I perform the modification, you can see that on property change gets called twice.

It gets called normally without any arguments using call a member name, but it also gets called with

name of can vote.

Now, why did this happen?

Well, it happened because my id jetbrains rider can see that can vote is affected by the age property

so it performs the change notification on can vote.

This is great.

It’s really great to have an IDE help me with this.

But unfortunately, as you may have guessed, this approach does not scale.

It does not scale for a number of reasons.

So, for example, if age depended on more properties, let’s say age depended on citizenship, for

example, then you would have even more code down here.

And then, you know, the IDE can miss a dependency at some point.

And also these dependencies, the way they are implemented, are not 100% correct.

So let me show you why they are not correct.

Imagine if age changes from 4 to 5.

We change the age from 4 to 5 now can vote for age four is false for age five is also false.

But we would be generating this invocation even though can vote has not in fact changed.

So what do you do if you want correct operation?

If you want to prevent notifications when the value has not in fact changed, well, then you have to

jump through hoops.

You have to cache the old value.

So you say old can vote, equals can vote, and then you perform all the changes on age.

And then you say, if old can vote is not equal to can vote, then yes, it did in fact change and then

you perform the notification.

But as you may have guessed, this approach does not scale.

If you have lots of dependencies, if you have a complicated dependency graph, then this is pretty

much impossible.

So we need to find some sort of way of dealing with all of this or at least some of these issues without

necessarily having to jump through hoops and write additional code in the setter because it’s a bit

unidiomatic to put so much code in the center.

The setter is supposed to just set the property.

It can do other things like notify, but it shouldn’t spawn off lots of notifications.

This has to be tucked away somewhere.

It has to be put into some other location, like a base class, for example.

So let’s try building a base class which actually manages the dependency graph of properties.

So we’ll have a class called Property Notification Support, and this is exactly where we’ll have NPC

implementation.

So we’ll implement a notify property change here.

We’ll have all the plumbing done here so that subsequently when we need to use this, we simply inherit

from this class property notification support.

Now already you can see a problem with this.

What if you want person to have a base class which is related to the domain hierarchy that you’re working

with?

Well, then you have a problem because you cannot inherit from two classes.

So you would have to rethink this somehow.

But let’s suppose that a base class spot is available and we add property change notification support

using this kind of base class.

So the idea is that inside this base class, we’re going to manage the entire dependency graph.

What I mean by that is we’ll have some sort of dictionary, so we’ll have a private read only dictionary.

And inside this dictionary we’re going to have a mapping from the name of the property to a set of properties

which are affected by it.

So hash set of string, let’s call it affected by affected by equals.

And let’s just put in a default constructor here.

Okay?

So the idea is as follows You have a property like can vote and we record the fact that this property

is affected by a hash set of things.

It can include H, but it can also include other things like citizenship, for example.

Okay.

So now obviously this on property change is not exactly complete because yes, we do have to invoke.

On the current property.

But we also have to look through all of the affected properties and we have to make notifications on

those as well.

So how would you do this?

Well, it’s easy because we already have a whole dictionary of them so we can just traverse them.

So for each var affected in affected by keys.

So we go through every single property inside this dictionary and we say, well, if the value.

So if affected by affected.

So if the set of affected properties contains the property name that’s currently being changed, then

we perform the notification.

So we call on property change providing the name of the affected property.

That’s pretty much it.

That allows us to traverse the entire graph because this call is recursive.

So when you call on property change, you end up here again and you do this for every single property,

which obviously can become a problem if you have circular dependencies.

So this is another thing where you would have to add additional code to make sure there are no circular

dependencies inside all of this.

Okay.

But we’ve got this base class and there is only one problem.

How do we actually enlist the fact, how do we record?

The fact that can vote depends on age, because right now the only way to do this is to do this by hand.

And we don’t really want to do this by hand.

We want some sort of automation.

Now, let me ask you a direct question.

Given this chunk of code, how would you find out what properties it refers to?

Well, the answer is you cannot you cannot take a getter and just traverse that getter and find out

all the information.

I’m sure you can do it by decompilation.

But seriously, you cannot do this.

The only way you can do this is if you change this to an expression tree.

Because expression trees can be traversed and you can find out all the properties that an expression

tree affects.

So that’s exactly what we’re going to do.

We’re going to change the structure of person.

We’re not going to have convert like this.

Instead, we’re going to have a bit of magic.

I’ll have a private read only function which returns a boolean called Convert.

Notice the lowercase here.

We’ll have a public boolean can vote that’s a property getter, but then actually uses this function.

It uses the function, can vote.

Now why do I have a function of boolean here?

Well, as you may have guessed, this is a result of a compilation of an expression tree.

Now where are we going to use this expression tree?

Well, unfortunately, we have to do this in the constructor.

We have to initialize, can vote in the constructor.

And the way we do this is as follows.

We say can vote equals.

And then I’ll use a method called property.

Now, this method is going to be defined in just a moment, but just trust me, it’s going to work fine.

So for a given property we give it its name of can vote and we also tell it what expression is used

to calculate it.

So in this case, the expression is that you have to have an age greater than or equal to 16, for example.

So that is that.

So now let’s define this property method because it’s also going to go into the base class, this class

that we have right here for property change notification support.

Now the property and the visitor that it uses are relatively complicated.

So instead of typing those out, I’m just going to paste both of them in and we’ll discuss them together.

Okay.

So here is a function called property of tea.

It takes an expression tree, an expression tree which uses one or more properties that it depends upon.

And so because it’s an expression tree, that means we can traverse it.

Expression trees are wonderful because you can traverse them and you can build visitors which traverse

them.

So in our case, we build a class called a Member Access Visitor.

This is just a private class, as you can see here, but it inherits from expression visitor, so it

knows how to visit expressions and how to find out certain parts about the expressions.

Now what parts do we care about?

Well, there’s only one thing we care about that is the affected property names.

Which property names are used in the calculation of the current property.

So when it comes to implementing the visit method, all we do is we look at the expression and we try

to find out whether or not we are accessing a member.

If we’re accessing a member, well, we can actually get the name.

Assuming the declaring type is correct, we can get the name and we can add it to the overall set of

property names.

That’s pretty much all that you need to do.

So at the end you have this public member called Property Names, which is a list of strings.

Now coming back up here, that’s the first thing we do.

So we make this visitor and we visit the expression, We get a set of property names, and if we do

have any property names, then we, first of all, make sure that they’re not already in the dictionary.

But if they are not So here we we create a new entry in the dictionary.

If they’re not there, and then we go through each of the property names and we add them to the dictionary,

that’s all.

So at the end of the invocation of this property method, you can make it uppercase if you want.

I’m keeping it lowercase here because it’s protected.

So at the end you are populating this dictionary right here.

You’re populating a dictionary specifying what properties affect, what properties.

So we’re building a graph behind the scenes.

And then, of course, what happens is after you’re done calling this, you end up with a function of.

Why do you end up with a function of Bu?

Well, because that’s what happens when you compile an expression tree.

So when you call here x dot compile your expression of func of t gets compiled into a func of T and

because in our case it’s a boolean, it gets turned into a func of boolean.

That’s exactly what we return.

So this func of boolean coming back down here actually gets stored in this variable.

And when somebody gets the voting status we call this particular function, which is wonderful.

So we no longer need property changed.

Obviously we no longer need any of this stuff because it’s already implemented in the base class and

we can start using this straight away so we can, for example, make a person.

We can track person changes just so that we get some diagnostic information.

So dot property changed.

Let’s just make a lambda here.

Let’s have let’s just write that some property has changed.

So Eventargs dot property name changed.

There we go.

Oh, don’t reformat it like this, please.

Okay.

And then we can try changing things.

Like I can say p dot h equals 15.

There we go.

Okay, so with this setup, let’s actually run this.

Let’s take a look at what happens.

Okay.

So as you can see, when we change the age, we also change can vote.

Now, one thing you might say is hold on.

This is not correct.

If age had an initial value of zero and you change it to 15, then Canva did not actually change.

So why are we notifying it here?

Well, the reason I’m doing it here is because I’m simply demonstrating the fact that the dependency

graph is stored correctly and we can see the the dependencies.

And let’s let’s add another dependency.

Let’s also have inside person a property for citizenship.

Only citizens can vote.

So we’ll have citizen get set and then I’ll use the magic of the ID to change it to a property with

change notification.

And here I’m going to say age greater than or equal to 16 and citizen.

There we go.

So now I can change the citizenship status by citizen equals true.

And we can run this and take a look at what the output is here.

So you can see age changed and Canva changed.

And then we citizen change and can vote has changed.

So this shows that the dependency graph works.

So what I’ve tried to show you is a shrink wrapped solution to the problem of dependencies between properties.

So you have a property and you have a set of properties which are affected by it.

And when it comes to doing the notifications on property change, then you first of all notify on the

property itself, but then you notify on all the affected properties as well.

So that’s good.

Obviously we haven’t solved all of the problems because we haven’t verified that the property has in

fact been modified.

We now have a dependency graph, but we call this dependency graph unconditionally, whereas we should

be calling it conditionally.

Now the implementation of this is even more complicated and I think we’re going outside the bounds of

describing this particular pattern.

So I’m going to leave it as a bit of a homework.

So your homework is to make sure that this invocation only happens when the affected property has in

fact been modified.

That’s it.

Play Play Play Play Play Play Stop Play Start Play information alert