Last time we saw how we can inject code at the beginning of generic methods. Today I will show you how to inject code in properties. I will cover the syntax for static classes as well.
So, let's start with a demo program that I will explain line-by-line.
using
System;
using
Telerik.CodeWeaver.Hook;
namespace
ConsoleApplication4
{
public
sealed
class
TargetClass1
{
public
TargetClass1(
string
text)
{
Text = InitText = text;
}
public
string
InitText {
get
;
private
set
; }
public
string
Text {
get
;
private
set
; }
public
int
Integer
{
set
{
throw
new
NotImplementedException(); }
}
}
public
static
class
TargetStaticClass
{
public
static
void
PrintText(
string
text)
{
Console.WriteLine(text);
}
}
class
Program
{
static
string
MyGetHook(TargetClass1 obj,
out
bool
skipOldMethodBody)
{
skipOldMethodBody =
true
;
Console.WriteLine(
"InitText='{0}'"
, obj.InitText);
return
"text2"
;
}
static
void
Main(
string
[] args)
{
Weaver<TargetClass1>
.AtStartOfGet<
string
>(_ => _.Text)
.InjectDelegate(
new
InjectPrologueFunc<TargetClass1,
string
>(MyGetHook));
var c =
new
TargetClass1(
"text1"
);
Console.WriteLine(c.Text);
Weaver<TargetClass1>
.AtStartOfSetOnly<
int
>((_, value) => { _.Integer = value; })
.Inject((integer) =>
{
Console.WriteLine(
"do some injection here..."
);
return
true
;
// skipOldMethodBody
});
c.Integer = 1;
Weaver.RegisterStaticClass(
typeof
(TargetStaticClass))
.AtStartOfAction<
string
>(text => TargetStaticClass.PrintText(text))
.Inject((text) =>
{
Console.WriteLine(
"text='{0}'"
, text);
return
true
;
// skipOldMethodBody
});
TargetStaticClass.PrintText(
"Hello world"
);
}
}
}
When we deal with properties we use the following set of methods:
The analogy with AtStartOfAction/AtStartOfFunc methods is obvious. However we handle property setters in a different way. If the property has both getter and setter we can use AtStartOfSet, if the property does not have getter we use AtStartOfSetOnly. Let's see the examples.
Weaver<TargetClass1>
.AtStartOfGet<
string
>(_ => _.Text)
.InjectDelegate(
new
InjectPrologueFunc<TargetClass1,
string
>(MyGetHook));
Here we declare we want to inject code in Text property of TargetClass1 type. Instead using AtStartOfFunc we use AtStartOfGet method. We then use generic delegate InjectPrologueFunc. For your convenience this delegate is defined in Telerk.CodeWeaver.Hook assembly. This is a slightly different than AtStartOfFunc/InjectDelegate where you have to define your own delegate type. Our injection method is defined according the rules we have already discussed in some of my previous posts. The method signature resembles the signature of the target method (that is the property getter) and there are the two additional parameters we discussed.
static
string
MyGetHook(TargetClass1 obj,
out
bool
skipOldMethodBody)
{
skipOldMethodBody =
true
;
Console.WriteLine(
"InitText='{0}'"
, obj.InitText);
return
"text2"
;
}
So far nothing new. You can think of AtStartOfGet method as of syntactic sugar.
Let's have a look at the second example.
Weaver<TargetClass1>
.AtStartOfSetOnly<
int
>((_, value) => { _.Integer = value; })
.Inject((value) =>
{
Console.WriteLine(
"do some injection here..."
);
return
true
;
// skipOldMethodBody
});
This time we have defined Integer property as a read-only one. In such scenarios we have to use AtStartOfSetOnly method. The only caveat is to put our property assignment in statement block. This is needed only because of the lambda expression. I would like to stress that the statement block should contain only the property assignment. Otherwise weaver library will not recognize the property we work with. Finally we define our injection via Inject method.
So far we saw how to do injection for properties. In my previous posts I've mentioned that working with static types is not much different than working with instance types. Let's see what the difference is.
Weaver.RegisterStaticClass(
typeof
(TargetStaticClass))
.AtStartOfAction<
string
>(text => TargetStaticClass.PrintText(text))
.Inject((text) =>
{
Console.WriteLine(
"text='{0}'"
, text);
return
true
;
// skipOldMethodBody
});
Because C# does not allow passing generic types as a generic type parameters we have to use another approach. This time we start with non-generic Weaver type and use RegisterStaticClass method. Then we pass the target type we want to work with. The other difference it the absence of the first parameter (the one named “_”) from AtStartOfAction method as there is no instance object. That is all the difference.
Probably you saw of felt that the API for dealing with properties and static classes is somewhat awkward. There are some inconsistencies as well. For example AtStartOfGet method chain allows us only InjectDelegate method while AtStartOfSetOnly method chain allows us only Inject method. We are aware of these issues and we are planning to fix them in the next releases. The API for dealing with static types will be changed as well. We plan to remove RegisterStaticClass method as it is redundant. If you are keen on using weaver API and have ideas how to improve it send us your feedback.
With this series of posts I covered most of the weaver library functionality. As we saw weaver API is very powerful and solves most isolation/mocking problems. Next time: how to mock types from mscorlib.
Mehfuz Hossain works as the Technical Advisor in DevTools Division . He is passionate playing around with the latest bits. He has been a Microsoft MVP, author of OS projects like LinqExtender and LINQ to flickr and most recently lighter (nodejs + mongo blogging engine). Prior to working at Telerik , Mehfuz worked as a core member in many high volume web applications including Pageflakes that is acquired by Live Universe in 2008. He is a frequent blogger and was also a contributor and site developer at dotnetslackers.com.