Esempio n. 1
0
        void ImplementStrategy(ImplementationStrategy strategy)
        {
            //Just in case...
            if (strategy.IsIgnored)
            {
                return;
            }
            if (strategy.Property.SetMethod.IsAbstract)
            {
                //This is an abstract property, we don't do these.
                throw new InvalidNotifierException();
            }

            switch (strategy.ImplementationStyle)
            {
            case ImplementationStyle.Inline:
                ImplementInline(strategy);
                break;

            case ImplementationStyle.Wrapped:
                ImplementWrapped(strategy);
                break;

            default: throw new NotImplementedException();
            }
            ContainsChanges = true;
        }
Esempio n. 2
0
        static void ImplementInline(ImplementationStrategy strategy)
        {
            var method = strategy.Property.SetMethod;
            var msil   = method.Body.GetILProcessor();
            var begin  = method.Body.Instructions.First();
            var end    = method.Body.Instructions.Last();

            if (strategy.NotificationStyle == NotificationStyle.OnSet)
            {
                InsertBefore(msil, msil.Create(OpCodes.Nop), begin);
                InsertBefore(msil, CallNotifyTargetInstructions(msil, strategy), end);
            }
            else
            {
                throw new BuildTaskErrorException("Inline implementation does not support OnChange notification");
            }
        }
Esempio n. 3
0
        static IEnumerable <Instruction> CallNotifyTargetInstructions(ILProcessor ilProcessor, ImplementationStrategy strategy)
        {
            foreach (var name in strategy.NotifyValues)
            {
                yield return(ilProcessor.Create(OpCodes.Ldarg_0));

                if (strategy.NotifyTarget.Parameters.Count > 0)
                {
                    yield return(ilProcessor.Create(OpCodes.Ldstr, name));
                }
                if (strategy.NotifyTarget.Parameters.Count > 1)
                {
                    yield return(ilProcessor.Create(OpCodes.Ldarg_1));

                    if (strategy.Property.PropertyType.IsValueType)
                    {
                        yield return(ilProcessor.Create(OpCodes.Box, strategy.Property.PropertyType));
                    }
                }
                var opCode = strategy.NotifyTargetDefinition.IsVirtual ? OpCodes.Callvirt : OpCodes.Call;
                yield return(ilProcessor.Create(opCode, strategy.NotifyTarget));

                yield return(ilProcessor.Create(OpCodes.Nop));
            }
        }
Esempio n. 4
0
        static void ImplementWrapped(ImplementationStrategy strategy)
        {
            var setMethod    = strategy.Property.SetMethod;
            var newMethod    = DuplicateMethod(setMethod, $"{setMethod.Name}`mist");
            var msil         = setMethod.Body.GetILProcessor();
            var instructions = new List <Instruction>();
            var rtn          = msil.Create(OpCodes.Ret);

            if (strategy.NotificationStyle == NotificationStyle.OnChange)
            {
                var boolType          = strategy.Property.Module.ImportReference(typeof(bool));
                var propertyType      = strategy.Property.PropertyType.Resolve();
                var equality          = strategy.Property.Module.ImportReference(defaultEqualsMethod);
                var equalityReference = equality.Resolve();

                var v1 = new VariableDefinition(strategy.Property.PropertyType);
                var v2 = new VariableDefinition(boolType);
                setMethod.Body.Variables.Add(v1);
                setMethod.Body.Variables.Add(v2);
                instructions.Add(msil.Create(OpCodes.Nop));

                if (propertyType.IsValueType)
                {
                    instructions.AddRange(
                        new[] {
                        msil.Create(OpCodes.Ldarg_0),
                        msil.Create(OpCodes.Call, strategy.Property.GetMethod),
                        msil.Create(OpCodes.Stloc_0),
                        msil.Create(OpCodes.Ldarg_0),
                        msil.Create(OpCodes.Ldarg_1),
                        msil.Create(OpCodes.Call, newMethod),
                        msil.Create(OpCodes.Ldloc_0),
                        msil.Create(OpCodes.Box, v1.VariableType),
                        msil.Create(OpCodes.Ldarg_1),
                        msil.Create(OpCodes.Box, v1.VariableType),
                        msil.Create(OpCodes.Call, equality),
                        msil.Create(OpCodes.Ldc_I4_0),
                        msil.Create(OpCodes.Ceq),
                        msil.Create(OpCodes.Stloc_1),
                        msil.Create(OpCodes.Ldloc_1),
                        msil.Create(OpCodes.Brfalse_S, rtn),
                    }
                        );
                }
                else
                {
                    instructions.AddRange(
                        new[] {
                        msil.Create(OpCodes.Ldarg_0),
                        msil.Create(OpCodes.Call, strategy.Property.GetMethod),
                        msil.Create(OpCodes.Stloc_0),
                        msil.Create(OpCodes.Ldarg_0),
                        msil.Create(OpCodes.Ldarg_1),
                        msil.Create(OpCodes.Call, newMethod),
                        msil.Create(OpCodes.Ldloc_0),
                        msil.Create(OpCodes.Ldarg_1),
                        msil.Create(OpCodes.Call, equality),
                        msil.Create(OpCodes.Ldc_I4_0),
                        msil.Create(OpCodes.Ceq),
                        msil.Create(OpCodes.Stloc_1),
                        msil.Create(OpCodes.Ldloc_1),
                        msil.Create(OpCodes.Brfalse_S, rtn)
                    }
                        );
                }

                instructions.AddRange(CallNotifyTargetInstructions(msil, strategy));
                instructions.Add(rtn);
            }
            else
            {
                instructions.AddRange(new[] {
                    msil.Create(OpCodes.Ldarg_0),
                    msil.Create(OpCodes.Ldarg_1),
                    msil.Create(OpCodes.Call, newMethod),
                });
                instructions.AddRange(CallNotifyTargetInstructions(msil, strategy));
                instructions.Add(rtn);
            }
            setMethod.Body.Instructions.Clear();
            foreach (var instruction in instructions)
            {
                setMethod.Body.Instructions.Add(instruction);
            }
            newMethod.DeclaringType.Methods.Add(newMethod);
        }