Lecture thumbnail 0:00 / 0:00 Local inversion of control is a trick.
It’s a trick for inverting the control of APIs so that instead of calling something on the subject,
you call it on the object.
Now, I know it sounds cryptic, so let me show you some examples of how it actually works.
I’ll make a class and let’s make a method for called Adding Numbers.
Now let’s suppose, for example, that we have a list.
So I have var list equals new lists, list of integers, for example.
And then I want to add a list item.
So I say something like list dot, add 20 for now, even though this is perfectly fine code and you
all do it every day, so there is no problem with it.
The problem is with readability, because this is not how we actually read instructions in English.
What we’re saying here is we’re saying something like the following.
We’re saying, Oh, hello list.
Can you please add to yourself the item with the value 24 And this is how you do in English.
In English we say add 24 to the list.
This is how we say it.
So the question is, can we implement it using C sharp APIs?
And the answer is, of course yes, we can.
Now, in order to do this, what I’m going to do is I’m going to define a class called extension Methods,
and we’ll make a couple of extension methods.
Now for this particular demo, I’m going to make a static function called add to add to.
And this is going to be generic.
So it’s going to operate on any type T And the idea here is the following.
So what we’re doing is we’re making an extension method on T, so we’re making an extension method that’s
going to work on any type.
Absolutely.
Any type.
That’s why there is a T in here, we’ll call it self and we’re going to add self to a collection.
So here we can say I collection of t called collection, for example.
So all we want to do and I forgot to add the return type here, which is also going to be T that’s actually
a fluent interface I’m making.
All I’m doing here is I’m saying collection dot add self and then I can also return self.
And this is going to be useful in just a moment.
So the idea is instead of writing it like this, you can say 24 dot, add two and add to the list.
Now I know that we’re paying the price of an extension method.
Call here to add something to the list.
However, the added benefit here is readability because essentially you can say you can read it in English,
you can say 24 gets added to the list.
It kind of reads from left to right.
In addition, of course, you can also add it to multiple lists.
So if this is something you need to do in your program and you have another list, you can say 24 dot
add two and then specify list two.
For example, this is a bit excessive and it’s actually not needed.
And the reason it’s not needed is because we can change this parameter.
And instead of having just a single collection that you’re adding the element to, I can make it a params
array specifying several collections and then we can just do for each var call in calls and this way
you add the element to every single collection.
So instead of saying 24 dot add to list dot add to list two, I can say 24 dot add to list comma list
two, but it’s still a fluent interface.
We still return self at the end of it.
So after we got the add to call, we can do something else.
For example, call another extension method which also operates on an integer.
Okay, so this is a simple example.
Now why is this inversion of control?
Well, the reason this is inversion of control is because typically it’s the list which controls the
operation of addition.
So here we say list dot, add.
So list is in control, but now we’re inverting control.
So instead of list being in control, it’s actually the value that’s being added, which happens to
be in control of the entire operation.
Okay, let’s take a look at another more complicated example.
Let’s suppose I have some function.
So I have a method called process command.
Let’s suppose that this process command takes some opcode and we want to check whether the opcode is
an and and or or an XOR.
And if it is one of those things, then we do something.
So typically you would write a typical C sharp code.
You say if opcode is equal to and or opcode is equal to or or opcode is equal to x or then do something.
Unfortunately, once again, even though this is correct code and there is nothing wrong with it, it’s
not very readable.
And what you’re basically saying is if opcode is and or opcode is or or opcode is X or then do something.
Whereas what you really want to say is something like if opcode is one.
Of the following and or x or.
Then do something so we can actually get this kind of API and there are different ways of doing it.
So some of the less efficient ways is something like the following.
You say if and then you make an array, so you make an array with and or and x or you say if this array
contains op code, then please do something.
Now this is better, but it’s still ugly.
Particularly the construction of the array is ugly.
So this part is particularly unpleasant.
And also you want to put the OP code first.
You want to say something like if OP code is one of the following and then make a list of the elements
so that you can subsequently kind of expand the elements and change them and so on.
Another approach which you see quite a lot in C sharp actually is when people put all the OP codes together,
so they say and or X or and then they go ahead and they split.
So you simply split the string on a space and then do contains op code.
Now this is also valid.
It’s also reasonably fast.
Of course it’s slower because you have to split the string, but it’s still not what we want to do.
We still want to have the separate elements for and or x or so we can expand it easily and we want the
thing to read in an English language.
So let’s comment this out.
Now, the implementation I’m going to make is going to use another extension function called is one
off.
So this extension method is going to check whether one of the values is in fact matching what you’re
looking for.
So we’ll have public static.
Bool is one of of T and this is going to once again be an extension method on T so it works on any type
and here we’ll have a params t value.
So these are the values we want to check against and we simply return values.
Dot contains self.
Now the great thing about this is that now what I can do is now I can write something like if and then
I can say if op code is one of and or x or.
Then do something.
And this is probably the best that we can come up with because now what’s happening is we’re getting
code which is readable from left to right.
We’re saying if opcode is one of the following and or X or then do something.
Okay, let’s do a final example.
Probably the more complicated example here.
Let’s suppose that I have a class called person and this class is going to have a list of names.
So it’s going to have a bunch of names and it’s going to have, let’s say, children list person, children,
also a list of people.
Okay, So we have this person.
Let’s suppose we want to have some function, which is called process, and it processes a person,
person, person.
Now let’s suppose that I want to check that the person has no names.
Let’s suppose no names have been defined.
Now how would you do it?
Now typically what you do is you say something like if person names dot count is equal to zero, which
once again, it’s it’s an okay chunk of code.
The only problem here is that it’s once again very unreadable in in English terms, because you’re basically
saying if person person’s names has a count of zero.
Now what is that count of zero?
That’s not great.
Now, of course, you can do it like this.
You can say if not person dot names dot any.
But once again, this is not very readable because of the leading, not the leading exclamation mark.
Basically what you’re saying here is you’re saying if the condition as follows does not hold, that
the person has any names and it’s just just a mouthful of words and it’s once again not great.
You want to say if person has any names, if person has no names.
And for this we once again turn to extension methods.
This time round, it’s going to be more complicated because instead of just taking the object and some
objects to match against, we’re going to have a function.
So I’m going to have a public static bool extension method called has no so person has no names, for
example.
So here has no is generic.
It takes t subject, which would be our person and it also has T, which would be in this case a string
because names is a bunch of strings.
So the name is has no the extension method works on the subject.
So this t subject self.
And instead of taking the names, what we’re going to do is we’re going to take a function.
Now, the reason we’re taking a function here is so that we can then write an accessor for this function
and have it in a readable form.
You’ll see it in a moment, but essentially it’s a function which takes T subject and it returns an
I enumerable of T, which is the properties.
So this is kind of the function for getting the properties.
And here we simply well, we return and we check whether the invocation of this function doesn’t give
us any value.
So we call props.
It’s a function we call it on self and we ensure that there are no values.
That’s why the exclamation mark.
So not any because we have has no.
Now the end result is we can write something like this.
We can say if person Dot has no and then write a lambda accessor for the names, for example.
Now what we end up with is a very readable chunk of code where saying if person has no names, then
please do something.
So it’s kind of readable from left to right.
Now let’s make a similar function for has some.
So I’m going to make another function.
Let’s call has some where you would remove the not from this location and now we can check that the
person has some names.
So has some names.
Okay.
Now we can be even smarter about this by chaining several of these together in kind of combinatorial
logic.
But for this, we need a temporary type.
We need a type which carries forward the information about the evaluation that we’ve just done, as
well as the object we evaluated this on.
So here what I’m going to do is I’m going to define a type called bool marker.
We’ll make it a struct, not a class bool marker of T, and here we’ll have the boolean result.
So public bool result.
We’ll also have the object that we operate upon which is public t self.
Now in addition, we’re going to define different operations that can combine several of these markers.
So I’m going to define public public enum.
Operation.
And this can be something like a nun.
If we haven’t done an operation yet, it can be an end or it can be an Or and we can add other ones
later on.
So here we’ll also have the internal field for this operation.
Let’s call it pending OP.
And now we can have a bunch of constructors so we can have a constructor for initializing every single
field here.
So C to F will give me a constructor which initializes everything, but we’re going to make this one.
Well, let’s make it internal actually, so that it’s not accessible.
So we make this one internal, but then of course we make a public one.
So let’s generate a constructor for our result and self.
And here, instead of performing the assignments, we’re going to call this other constructor that we’ve
made and we’re going to call it with a default value of none.
So here, result self and then the value of none.
Meaning we haven’t performed any operation yet.
Now, having made this, we’re going to change the return types on our extension method.
So instead of returning Boolean, we’re going to start returning these boolean markers.
So bool marker of T subject, this is how we’re going to do it and I’m going to do the same thing for
this extension method.
So now we need to change the return values.
Obviously we need to return these blue markers where the second argument is the self and we’re going
to do the same thing here.
New bool marker and then the arguments.
So first of all, the actual check and then the object we invoke this upon.
And now, of course, we have a chunk of broken code here because this is no longer a Boolean.
So we need to cast an implicit conversion operator, make an implicit conversion operator to turn it
into a boolean by simply getting the result.
So here I’ll say public static implicit operator bool, which takes a bool marker of T.
And simply returns its result.
So we simply return marker dot result.
Okay, so what does this give us?
Why did we just introduce a new type?
Now the answer is that we can try and combine them using these operations.
So, for example, if I want to combine two bool markers using the and operator, I can say something
like the following.
I can say public bool marker of T.
And and this is going to be a property which returns a new bool marker, which is a copy of the current.
So this dot result and this dot self, actually we don’t need this in both of these cases.
But the last argument is going to be operator and so operation and gets added here.
Okay So you’ll see why this is done in a moment because we’re going to add new extension methods which
are now going to operate not on t subject but on bool markers.
So, for example, what I can do is I can define the following.
I can define a new has no extension method, which is going to be look like the following.
So we’ll have bool marker of T has no and then this is going to be on T and u and it takes a bool marker.
So it’s an extension method on bool marker of T, which is the marker we once again take a function.
So here we have a func which takes a T and returns an enumerable of u.
So use the type of the property, let’s call it props.
Now here is the interesting thing.
If the marker we’ve got has a pending and operation and it’s false, we don’t need to do anything because
the condition has failed.
So we say if marker dot pending operation is equal to operation and.
And the result is false and not marker dot result.
Then we can simply return the current marker because it’s already failed.
Otherwise we do the invocation and we return a new boolean marker where we do the same invocation as
above.
So we do all of this, but we do it with a marker obviously.
So not props of marker dot self dot any.
And then the second argument is marker dot self, thereby making a new marker.
Now what does this give us?
I wonder?
And it gives us the ability to write the following.
So here we wrote person dot has some and if we want to check that the person has some names but no children,
we can say if person has some P goes to P dot names, dot and dot has no and then p p dot children.
So this way what we’ve ended up with is a very fluent and very readable construct for being able to
check the presence or absence of particular properties.
So here we can say if person has some names and has no children, it reads from left to right as it
does in English, and that is the entire goal of the local inversion of control.
Play Play Play Stop Play Play Play information alert