C# and AOP - AOPAlliance (Aspect-oriented programming) how does this work
Asked Answered
B

1

6

I just had a very interesting experience with AOP in C#. I have a function with a return type List which is being intercepted and that's all well and good. However the interceptor function is a validator style function and can prevent the real function by being called and returning the boolean false.

So the code looks a little bit like this:

List<Update> updates = Manager.ValidateAndCreate();

// protected void Save(List<Update> updates) { ....
Save(updates);

The Method Interceptor looks like the following

public class ExceptionAdvice : AopAlliance.Intercept.IMethodInterceptor {

    public object Invoke(AopAlliance.Intercept.IMethodInvocation invocation) {

        if (isValid(invocation)) {
            return invocation.Proceed();
        } else {
            return false;
        }
    }

    private bool isValid( ...
 }

Now after validation fails the value of updates is actually a boolean not a List, I thought there would be some kind of runtime error here but there was not, so:

updates.GetType().Name == "Boolean"

But:

updates is bool == false

So save will still accept its mutated list of updates and will complain later on when you try to use it.

So how is this possible in a type safe language like C#? btw it's spring-aop.

Edit: Also this does compile and it does work i've stepped through it a few times now.

Bracket answered 26/8, 2011 at 6:2 Comment(6)
Also I'll point out that this is C# 3.5 so there is no Dynamic or anythingBracket
I don't believe this is possible, is your program still compiling once u explicitly type the return? Is your debug file out of date?Presume
@Presume I've updated the question again, hope it helpsBracket
AOP is a general programming concept. C# doesn't fully support AOP out of the box. AOPAlliance seems to be a third-party framework (part of Spring.NET?) designed to support AOP. Can you change the title/tags to reflect this?Brazenfaced
@Lavinski: What is the exact signature (return type) of Manager.ValidateAndCreate();? Are you proxying an interface or are you using an inheritance based proxy?Kurtzman
@Kurtzman The actual return type is List<Update>Bracket
P
6

I believe this is possible because Spring.Net is emitting proxy classes at runtime which skip compile time type checks.

It essentially implements a decorator pattern wrapping the original class and dynamically generating a new method implementation. In the dynamically generated proxy method the return type can be changed when it writes the IL, and .NET allows it because it doesn't check the type at runtime. At compile time of course it's also still perfectly valid. This leads to the rather weird scenario above whereby your static type is actually different to the runtime type.

The following is true because it's checking the actual runtime type, which can in cases resolve to Boolean.

updates.GetType().Name == "Boolean"

But the following fails because it's comparing the static type of the variable to Boolean, which it's not.

updates is bool == false

I would recommend that you don't change the type within Invoke.

Presume answered 27/8, 2011 at 1:30 Comment(6)
+1: It's probably a better idea to raise an event or throw an exception anyway.Christoper
@Presume - Spring.net doesn't create proxies with a different method signature. A proxy implements the interface(s) implemented by the target instance, or (in the case of an inheritance based proxy) implements all public virtual members of the target instance.Kurtzman
@TheCodeKing: I just ran a quick test; as expected Spring.Aop throws an InvalidCastException when I try to return another type. OP's scenario can only happen if Manager.ValidateAndCreate(); has return type object.Kurtzman
But then obviously OP's code example "that looks a little bit like this" wouldn't compile, so I'm a bit at a loss here.Kurtzman
I've reworded slightly to clarify the method signature remains the same, it's just the proxy implementation that returns a different type. I've reproduced this in VS, in debugger the type shows as System.Collections.Generic.List<string> {bool}.Presume
Basically the proxy implementation returns the result of the method invocation chain in IL and this is not typed checked at runtime. You can recreate the scenario by emitting a method in IL, and returning the wrong type.Presume

© 2022 - 2024 — McMap. All rights reserved.