We use the very same API to do injections in generic methods. However this time I will start with relatively more complex scenarios. At first the syntax may look awkward but once you know the foundations everything comes to place. Lets see the target method in our first scenario.

internal V TargetMethod<U, V>( out U u,

V[] v,

Dictionary<U, List<V>> dictUV)

where U : IDisposable

where V : U

{

throw new NotImplementedException();

}

As we learned from my previous post we have to define a delegate and according the rule we have to add 2 new parameters. So here is the delegate:

delegate V PrologueDelegate1<U, V>( out U u,

V[] v,

Dictionary<U, List<V>> dictUV,

TargetClass1 obj,

out bool skipOldMethodBody)

where U : IDisposable

where V : U;

Lets recall that the next-to-last parameter holds the instance on which the target method is called so it must have type TargetClass1. Lets recall that the last parameter is flow control flag. Once the delegate is defined we have to define our prologue injection.

static V PrologueInjection1<U, V>( out U u,

V[] v,

Dictionary<U, List<V>> dictUV,

TargetClass1 obj,

out bool skipOldMethodBody)

where U : IDisposable

where V : U

{

skipOldMethodBody = true;

u = default(U);

Console.WriteLine("::PrologueInjection1<{0}, {1}>",

typeof(U),

typeof(V));

return default(V);

}

Here we define that we want to print a simple trace and to skip the target method body (as it throws NotImplementedException). So far nothing new. Lets see how we define our injection.

The syntax looks heavy especially the second line. But looking closely we see that it just resembles the signature of the target method. Actually it follows the rules defined by System.Func<...> delegate and we substitute the generic type parameters with concrete types. The only caveat is the second type parameter. We define it as Derived[] not as Derived. This is because the lambda expression has to match the target method signature. With little practice one should be able to define complex injections as fast as one can type ;)

After we define our injection we create new object instance and call the target method:

new TargetClass1().TargetMethod<Base, Derived>(out arg1, null, null);

Let see our second scenario. This time we have a generic method defined in generic class. There is more. The target method uses the generic types parameters from the declaring type.

class TargetClass2<T>

{

internal void TargetMethod<U, V>(T t, Dictionary<U, V> dictUV)

{

....

}

}

A reasonable question arises: how do we define a delegate for such method? One of the options is to include the generic type parameters of the declaring type as well. Weaver library takes this approach. So the delegate looks like:

delegate void PrologueDelegate2<T, U, V>( T t,

Dictionary<U, V> dict,

TargetClass2<T> obj,

out bool skipOldMethodBody);

First we include the generic type parameters of the declaring type (in the order they are defined) then we include the generic type parameters of the target method (in the order they are defined). We follow the rule for adding 2 new parameters – one that hold the object instance on which the target method is called and one for the flow control flag. As we can see there is nothing new.

Wait a second! In the first scenario we did injection for Base and Derived types and called the target method for the very same types. However in the second scenario we defined injection for <bool, char, double> tuple and called the target method for <int, float, string> tuple. Well the actual types used for injection definition serve only one goal – to allow the compiler to compile you code. As we saw in the first scenario there are constraints on the generic type parameters. So we have to satisfy these constraints. I would recommend using <object, object, …, object> tuple where possible. This reduces the noise in your source code while keep it consistent.

So far we saw to do prologue/epilogue injections for most kinds of instance methods. Next time I will post how to do injections for static methods, properties and unsafe methods. Stay tuned.

Register for a free
webinar this Thursday, Jul 22, 11 am EST and check out What’s
New in JustCode, JustMock, and OpenAccess ORM. During the live event
attendees will also have the chance to win a Telerik Ultimate Collection
(valued at $1999).

Mehfuz Hossain

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.

Progress, Telerik, and certain product names used herein are trademarks or registered trademarks of Progress Software Corporation and/or one of its subsidiaries or affiliates in the U.S. and/or other countries. See Trademarks or appropriate markings.