1

While I'm testing the Castle DynamicProxy I found an weird behavior

I didn't found good documentation, so the closer information I found was theses 2 ask Castle Dynamic Proxy not intercepting method calls when invoked from within the class and Why won't DynamicProxy's interceptor get called for *each* virtual method call?

and with it, I suppose that, when you use the CreateClassProxyWithTarget everything goes into the Class and back to the proxy, so if the Prop/function is not virtual, it only return the Class value.

I guess, with code sample, my question get clear.

Let's suppose I have this code

Main

private static void Main(string[] args)
{
    var theObj = new SomeClass
    {
        NonVirtualString = "Non virtual value",
        VirtualString = "Virtual value"
    };
    var theProxy = Interceptor.AddProxy(theObj);

    Console.WriteLine($"OBJ NonVirtualString: {theObj.NonVirtualString } || VisrtualString {theObj.VirtualString }");
    Console.WriteLine($"Proxy NonVirtualString: {theProxy.NonVirtualString } || VisrtualString {theProxy.VirtualString }");
}


public class SomeClass
{
    public string NonVirtualString { get; set; }
    public virtual string VirtualString { get; set; }
}

Interceptor

public static class Interceptor
{
    private static readonly ProxyGenerator _generator = new ProxyGenerator();

    public static TEntity AddProxy<TEntity>(TEntity entity) where TEntity: class, new()
    {
        var proxy = _generator.CreateClassProxyWithTarget(entity, new LogInterceptor());
        return proxy;
    }
}

Logger

[Serializable]
public class LogInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        try
        {
            invocation.Proceed();
            Console.WriteLine("Intercepting: {0} with value: {1}", invocation.Method.Name, invocation.ReturnValue);
        }
        catch (Exception ex)
        {
            Console.WriteLine(string.Format("Exception in method {0}{1}{2}", invocation.Method.Name,
                                            Environment.NewLine, ex.Message));
            throw;
        }
    }
}

the result is

OBJ NonVirtualString: Non virtual value || VisrtualString Virtual value

Intercepting: get_VirtualString with value: Virtual value

Proxy NonVirtualString: NULL || VisrtualString Virtual value

And the expected result would be

OBJ NonVirtualString: Non virtual value || VisrtualString Virtual value

Intercepting: get_VirtualString with value: Virtual value

Proxy NonVirtualString: Non virtual value || VisrtualString Virtual value

So, if the result is right, how I can do, with Castle or other Lib what I'm trying(Only overhide the virtual and keep the non virtual accessible ?

Community
  • 1
  • 1
Nicollas Braga
  • 802
  • 7
  • 27

2 Answers2

2

You probably can't. Not with the composition-based CreateClassProxyWithTarget, anyway. When you are calling a non-virtual method on such a proxy object, you're completely bypassing DynamicProxy; it cannot intercept that invocation and therefore won't forward it to the target object. Thus you get back the value of the proxy object's own uninitialized NonVirtualString property.

You could get this to work with inheritance-based proxying, i.e. with CreateClassProxy. Using that approach, you'll only have one object (the proxy) instead of two, so you'd set the property values directly on the proxy object instead of on a separate target. Then, even though DynamicProxy still won't be able to intercept the call to NonVirtualString's getter, the call will just use the original class' getter.

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
0

Because the property is not virtual the proxy class cannot override it. When you call Interceptor.AddProxy() it creates a new object of type that inherits from SomeClass. This object will have its own values of VirtualString and NonVirtualString. VirtualString Will be overridden by the library to use Interceptor, but NonVirtualString will not be overriden and will remain NULL, as it's the default for string.

You might try to use Interface interception instead. Otherwise, you won't be able to intercept a non virtual methods/properties.

DevNewb
  • 841
  • 7
  • 19