Telerik blogs

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:

  • AtStartOfGet
  • AtStartOfSet
  • AtStartOfSetOnly
  • AtStartOfStaticGet
  • AtStartOfStaticSet
  • AtStartOfStaticSetOnly

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.


About the Author

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.

@mehfuzh

Comments

Comments are disabled in preview mode.