Lecture thumbnail 0:00 / 0:00 With proxies like with other components which wrap other components.
You basically have a choice between static and dynamic, and certainly static is going to be the faster
option, the preferred option.
But sometimes you want something called a dynamic proxy, and that is a proxy which is constructed at
runtime with all the associated performance costs.
So we’re going to take a look at how a dynamic proxy works.
So here I have an interface called I Bank Account, and I have an implementation with a bank account
which actually does the typical deposit and withdraw operations.
Now one of the things I want to do is I want to implement logging.
So I want to note the number of times that somebody calls the withdraw or deposit method or indeed any
other method in bank account.
And I don’t want to re-implement every single method and proxy over the calls that way.
Instead, I want a dynamic proxy.
So what you’ll see here in the references is I have a reference to impromptu interface, which is a
very useful library, very useful NuGet package for actually generating the appropriate interface,
any interface that you want on a dynamic object.
Now, why is this relevant?
Well, we’ll see in just a moment.
So here I have a scenario for actually working with the bank account.
I’m making a bank account and I’m depositing 100 and I’m withdrawing $50 and then I’m outputting the
information about the bank account.
So we have some output here.
But in addition, what I’m going to do right now is I’m going to actually log all of this information.
So I’m going to keep actually a record of how many times each of the methods inside bank account was
called.
So this is going to be a bit complicated, but also really cool.
So we’re going to have a class called Log of T, So this class called Log of T is going to inherit from
dynamic object.
So you can see we’re using the DLR here.
In addition, we’ll put some constraints on the T argument.
So we’ll say that T has to be a class and it has to have a default constructor.
There we go.
Now we want to keep the number of calls to each of the methods of T.
So what I’m going to do is I’m going to have a private dictionary.
We going to have a private dictionary from string to INT.
So string is the name of the method and int is the number of times the method was called.
So this is going to be called method call count.
So let’s initialize it with the default here.
And in addition, what I’m going to actually keep is I’m going to keep a reference to the subject,
a reference to the object whose calls were actually intercepting.
So this is going to be private only t subject.
There we go.
Okay.
So the idea is that you make the log so you have a constructor and the constructor takes the subject.
So here is t subject.
We simply assign it.
So we say this dot subject equals subject, and that’s pretty much it.
But the key thing here is we’re going to make a factory method, which is going to be very sly.
We’re going to have a factory method which is going to force our dynamic object to behave as if it implements
a particular interface.
And in our case, the interface is a bank account, but we also want logging.
So that’s something that we’ll have to implement as well.
So first of all, let’s deal with the logging.
That’s the first thing that we need to do.
So in order to implement logging, since we’re in a dynamic object, what we can do is the following.
We can go ahead.
And if we’re going to generate code for a second, we’re going to override.
Let’s go into overriding members here and we’re going to override, try invoke member.
So that’s a dynamic object method which is used whenever somebody wants to invoke something on this
object.
So here I’m going to get rid of the default implementation because we’re going to do something customized.
We’re going to try and actually invoke the member, but also log their invocation.
So let’s put a typical try catch and here I’ll actually get rid of the exception.
I’m not going to log the exception itself.
Instead, I will just specify the result.
So essentially when you do try invoke member, you have this out object result and if you fail, then
we may as well just set it to null.
So I’m going to say result equals null and I will return false because we failed.
Otherwise we’re going to do the following.
So somebody is invoking some member on a dynamic object.
So what do you do?
Well, first of all, we want to write some information.
Let’s just output a bit of info.
So we’re invoking invoking and we can get the actual name of the object that we’re invoking this on.
So this would be subject subject dot, get type dot name.
So we’re invoking this class’s dot and then we can get the binder dot name, which gives us the name
of the method that we’re invoking with arguments.
And here we can actually specify the arguments.
So for the arguments we can just do a string dot, join over the args.
So notice here, let me just scroll left here.
We have the arguments, so we’re going to have them in here.
So I will have with.
Let’s put square brackets in here, then curly braces, then I’ll do string dot, join with a comma
and I’ll just put the args in here.
They’ll all be converted to strings.
There we go.
So this is some diagnostic information.
But then of course, what we want to do is we want to perform even more logging by adding the method
called counts.
We’re keeping the total number of methods.
So if method call count contains key.
So we’ve already invoked this method with binder dot name, we just increment.
So we say method call count at binder dot name plus plus.
There we go.
Otherwise we added.
Is that okay?
Yeah, that should be binder by the way.
Binder like so.
Otherwise we add the key.
So we say else method call count dot add with binder dot name and it’s been called once.
So we add a one in here and then of course we set the result.
We have to set the result of the actual invocation.
So here what we do is we say result equals subject dot get type, get method with the name.
So we get the appropriate method with binder dot name, and then we invoke it.
So we invoke it with on the subject with the arguments.
There we go.
So that’s how you actually perform the call and then you return.
True, because everything’s exceeded obviously.
So that’s the way of implementing try invoke member on a dynamic object while at the same time implementing
logging.
So now all we have to do well, we have two things to do.
First of all, we have to make tea or log of tea.
Give us an interface that we want.
So we want an arbitrary interface to be exposed.
And the way this is done is using a generic factory method.
So we’re going to have public static AI.
So AI is going to be the interface type.
I’m going to call this as with the interface type argument, and once again I’ll put some constraints.
So AI has to be a class, although strictly speaking, has to be an interface.
And here if it’s not of an interface type, we may as well throw an exception.
So if type of AI is not an interface, so is interface.
Then we can throw new argument exception where we can complain.
I must be an interface type.
There we go.
Okay, so what we do now is we use the impromptu interface library that we included via a NuGet package
and we return something interesting.
We return a new log of T, so we return a new instance of us effectively taking a new T so we construct
the object that we’re returning and then we invoke act like and this is the impromptu interface part,
as you can see in the code completion here.
So act like AI.
So we get the dynamic object to act as if it implemented this particular interface, because it really
does, because when you invoke the members, it’s going to be dynamic anyway.
So it’s going to implement any interface that you want.
So this is the approach.
And now what we need to do is the final part, which is writing out some info about all those invocations.
So I’m going to have public string info here with a getter and what I’m going to do is just make a string
builder.
I’m going to append the information about every single call.
So we’re going to do for each var cave in method call count.
So that’s the key value.
So I’m going to append line here.
I’m going to append lines.
First of all, key value dot key called cave value times.
Or if it’s one time, it’s going to be time.
So we’ll put these in round brackets and I’ll return SB dot two string as always, and that’s our dynamic
proxy completed.
So now we can start using it.
So instead of having a bank account here, what we’re going to do is we’re going to make a log of bank
account as a bank account.
So it’s a bit tricky.
So we’re making a dynamic proxy, which is going to log calls to a bank account, but then we’re returning
it as an interface of a bank account.
That’s what the impromptu interface does.
It basically gives you the interface that you want from a dynamic object.
So even though this is a dynamic object which proxies the calls over to the actual subject which we
are constructing here, it’s actually going to work out okay with the interface.
So now we have code completion on that interface because BA is of type I bank account, so all the interface
members are available.
It’s not like a pure dynamic object where you get node code completion because nobody knows what members
it has and then we can write line BA, but in addition we can also, I guess, output some of the information
about this object.
So in this case, what we can do is we can write line ba.info like so and you’ll notice that info is
actually available because we have that, we have that interface for the, the actual I bank account
instead of having it for the overall dynamic object.
So we have this log of T and this method call count is being.
But it’s not exposed in the actual object.
So how do you actually get it to be output?
Well, one of the ways we can do this and it’s a bit tricky is we’re going to override two string here.
So first of all, let me just run this.
Let me run this to prove to you that the whole thing is almost the same.
But notice the last line.
So everything is okay.
We are intercepting the invocations.
Here is the actual dynamic proxy invocation logging here.
So invoking bank account deposit with arguments so and so.
However, look at the last line.
The implementation to string is completely broken and the reason why the implementation is broken is
because we’re now taking two string from the dynamic object.
And so we’re getting just its default implementation.
So what we’re going to do is we’re going to use this info that we’ve defined in an override of two strings.
So I’m going to override two string here.
Oh, like so.
And I’m going to use info.
So I’m going to return dollar and then I’ll put the info here and then I will put the subject here as
well, maybe with a line break in between.
Okay, so let’s go ahead and run this.
We should get more information now so you can see that we’re getting statistics now.
So we’re getting statistics on the method calls.
We called deposit one time and we call withdrawal one time.
So we recorded all the information.
And then we’re getting also the two string from the original object as well.
So this is how you build a dynamic proxy.
Obviously, you’re paying the performance cost in terms of the dynamic construction of the object,
but you’re getting the flexibility and you certainly don’t have to re-implement every single interface
member.
You can just intercept them using try invoke member.
And the neat trick with the impromptu interface allows you to have your dynamic object acting as if
it were implementing a particular interface, which is very handy.
Play Play Play Play Play Play Stop Play Play Start Play Play information alert