wliao008 / buffalo

an aspect oriented programming framework using mono cecil for the .NET platform
1 stars 0 forks source link

Type unboxing problem #16

Closed wliao008 closed 11 years ago

wliao008 commented 11 years ago

Example program:

 class Program
    {
        static TraceAspectTester test = new TraceAspectTester();
        static void Main(string[] args)
        {
            var result = test.divide(6, 3);
            Console.WriteLine("result: " + result);
        }
    }

    public class TraceAspectTester
    {
        [DoubleAspect]
        public double divide(int a, int b)
        {
            return a / b;
        }
    }

The Around aspect:

    public class DoubleAspect : MethodAroundAspect
    {
        public override object Invoke(MethodArgs args)
        {
            Console.WriteLine("Enter a num: ");
            int num = int.Parse(Console.ReadLine());
            if (num % 2 == 0)
                return args.Proceed();
            else
                return -1;
        }
    }

Generated MSIL:

.method public hidebysig virtual 
    instance object Invoke (
        class [Buffalo]Buffalo.MethodArgs args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 119 (0x77)
    .maxstack 4
    .locals init (
        [0] int32,
        [1] object,
        [2] bool,
        [3] object,
        [4] object[],
        [5] object
    )

    IL_0000: nop
    IL_0001: ldstr "Enter a num: "
    IL_0006: call void [mscorlib]System.Console::WriteLine(string)
    IL_000b: nop
    IL_000c: call string [mscorlib]System.Console::ReadLine()
    IL_0011: call int32 [mscorlib]System.Int32::Parse(string)
    IL_0016: stloc.0
    IL_0017: ldloc.0
    IL_0018: ldc.i4.2
    IL_0019: rem
    IL_001a: ldc.i4.0
    IL_001b: ceq
    IL_001d: ldc.i4.0
    IL_001e: ceq
    IL_0020: stloc.2
    IL_0021: ldloc.2
    IL_0022: brtrue.s IL_006c

    IL_0024: ldarg.1
    IL_0025: callvirt instance object [Buffalo]Buffalo.MethodArgs::get_Instance()
    IL_002a: stloc 3
    IL_002e: ldarg.1
    IL_002f: callvirt instance object[] [Buffalo]Buffalo.MethodArgs::get_ParameterArray()
    IL_0034: stloc 4
    IL_0038: ldloc 3
    IL_003c: unbox.any client.TraceAspectTester
    IL_0041: ldloc 4
    IL_0045: ldc.i4 0
    IL_004a: ldelem.ref
    IL_004b: unbox.any [mscorlib]System.Int32
    IL_0050: ldloc 4
    IL_0054: ldc.i4 1
    IL_0059: ldelem.ref
    IL_005a: unbox.any [mscorlib]System.Int32
    IL_005f: callvirt instance float64 client.TraceAspectTester::divide(int32, int32)
    IL_0064: box [mscorlib]System.Double
    IL_0069: stloc.1
    IL_006a: br.s IL_0075

    IL_006c: ldc.i4.m1
    IL_006d: box [mscorlib]System.Int32
    IL_0072: stloc.1
    IL_0073: br.s IL_0075

    IL_0075: ldloc.1
    IL_0076: ret
} // end of method DoubleAspect::Invoke

The program compiles fine and MSIL displays ok, but when execute the modified program, the following error occurred:

client_modified.exe Enter a num: 5

Unhandled Exception: System.InvalidCastException: Specified cast is not valid. at client.TraceAspectTester.divide634878808119716310(Int32 a, Int32 b) at client.Program.Main(String[] args)

wliao008 commented 11 years ago

I think the problem is with boxing and unboxing of the returned type. If I changed the aspect to return -1.0 everything works fine.

wliao008 commented 11 years ago

It seems this is the expected behavior, we can only unbox a value type to its original type (and the nullable version of that type)

int i = 1;
object o = i;
double d = (double)o; // <--- this will cause InvalidCastException
Console.WriteLine("d: " + d);
Console.WriteLine("Done");
Console.Read();

check stackoverflow post at http://stackoverflow.com/q/1085097/150607