Solved problem of getting virtual method from constructors in DynamicProxy
I encountered a problem in Dynamic Proxy, it threw a null reference exception when I tried to run the following code:
The reason was that ArrayList::ctor(ICollection ) calls a virtual method, and since Dynamic Proxy intercept all dynamic calls, it recieved the call, but before it had time to initialize itself, so it tried to reference a null pointer.
I was quite lost as to what to do, this is something that users of Rhino Mocks would likely want to do, and it's a certainly a general problem. I thought that there must be a way to solve that:
{
protected virtual void Init() {}
public Base() { Init(); }
}
public class Derived : Base
{
string str = "{0}.{1}";
protected override void Init() { str = string.Format(str,1,2); }
public Derived() { /*do more work*/ }
}
public class Derived2 : Base
{
string str;
protected override void Init() { str = string.Format(str,1,2); }
public Derived2() { str = "{0}.{1}"
Calling new Derived() will succeed, but calling new Derived2() will fail with null reference exception. Here are the IL for Derived2's constructor:
{
// Code Size: 18 byte(s)
.maxstack 2
L_0000: ldarg.0
L_0001: call instance void Base::.ctor()
L_0006: ldarg.0
L_0007: ldstr "{0}.{1}"
L_000c: stfld string Derived2::str
L_0011: ret
}
The constructor for Base is called, which will call init, which will reference str, which is a null, since we set it only after we call Base' constructor. Here is the IL for Derived's constructor:
{
// Code Size: 18 byte(s)
.maxstack 2
L_0000: ldarg.0
L_0001: ldstr "{0}.{1}"
L_0006: stfld string Derived::str
L_000b: ldarg.0
L_000c: call instance void Base::.ctor()
L_0011: ret
}
Here we can see the difference, we first set str, and only then we will call Base' constructor, so this version works.
When I figured out what the difference was (and it took some time, I'm not used to reading IL) I approached Dynamic Proxy with dread, I know just about zilch about Reflection.Emit, and Dynamic Proxy has another layer on top of that. However, in the end it took less than an hour, to grok source that I saw for the first time, and then make the changes (moving four lines, that was it). I sent the patch to Castle Project, and I hope they will accept it.
On that note, I'm getting more and more curious about CastleProject's other products, especially Aspect#, MonoRail & Windsor.
Comments
Comment preview