Ejemplo n.º 1
0
        private static void AddPropertyInitializeInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var declaringType         = member.Property.OriginType;
            var syncRoot              = new __ISyncRoot();
            var legalInitInterceptors = member.InterceptorInfos.Where(x => x.InterfaceInitializer != null).ToArray();
            var relevantCtors         = member.Property.IsStatic ? new Method[] { declaringType.StaticConstructor } : declaringType.GetRelevantConstructors().Where(x => x.Name != ".cctor");

            foreach (var ctor in relevantCtors)
            {
                ctor.NewCode()
                .Context(x =>
                {
                    for (int i = 0; i < legalInitInterceptors.Length; i++)
                    {
                        var item  = legalInitInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];

                        x.Assign(field).NewObj(item.Attribute);
                        if (item.HasSyncRootInterface)
                        {
                            x.Load(field).As(__ISyncRoot.Type.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }

                        ImplementAssignMethodAttribute(builder, legalInitInterceptors[i].AssignMethodAttributeInfos, field, item.Attribute.Attribute.Type, x);
                    }

                    x.Assign(propertyField)
                    .NewObj(propertyInterceptionInfo.Ctor,
                            member.Property.Getter,
                            member.Property.Setter,
                            member.Property.Name,
                            member.Property.ReturnType,
                            Crumb.This,
                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                            propertySetter == null ? null : x.NewCode().NewObj(actionObjectCtor, propertySetter));

                    for (int i = 0; i < legalInitInterceptors.Length; i++)
                    {
                        var item  = legalInitInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(item.InterfaceInitializer.ToBuilderType)
                        .Call(item.InterfaceInitializer.OnInitialize, propertyField, member.Property.BackingField);
                    }
                })
                .Insert(InsertionPosition.Beginning);
            }
        }
        private static void AddPropertySetterInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var syncRoot = new __ISyncRoot(builder);
            var legalSetterInterceptors = member.InterceptorInfos.Where(x => x.InterfaceSetter != null).ToArray();

            member.Property.Setter
            .NewCode()
            .Context(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).IsNull().Then(y =>
                    {
                        y.Assign(field).NewObj(item.Attribute);

                        if (item.HasSyncRootInterface)
                        {
                            y.Load(field).As(syncRoot.Type.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }
                    });
                    item.Attribute.Remove();
                }

                x.Load(propertyField).IsNull().Then(y =>
                                                    y.Assign(propertyField)
                                                    .NewObj(propertyInterceptionInfo.Ctor,
                                                            member.Property.Getter,
                                                            member.Property.Setter,
                                                            member.Property.Name,
                                                            member.Property.ReturnType,
                                                            y.This,
                                                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                                                            y.NewCode().NewObj(actionObjectCtor, propertySetter)));
            })
            .Try(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(item.InterfaceSetter.OnSet, propertyField, member.Property.BackingField, member.Property.Setter.NewCode().GetParameter(0));

                    x.IsFalse().Then(y => y.Assign(member.Property.BackingField).Set(member.Property.Setter.NewCode().GetParameter(0)));
                }
            })
            .Catch(typeof(Exception), x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(legalSetterInterceptors[i].InterfaceSetter.OnException, x.Exception);
                }

                x.Rethrow();
            })
            .Finally(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(legalSetterInterceptors[i].InterfaceSetter.OnExit);
                }
            })
            .EndTry()
            .Return()
            .Replace();
        }
        private void InterceptProperties(Builder builder, IEnumerable <BuilderType> attributes)
        {
            if (!attributes.Any())
            {
                return;
            }

            var stopwatch = Stopwatch.StartNew();

            var iPropertyGetterInterceptor = new __IPropertyGetterInterceptor(builder);
            var iPropertySetterInterceptor = new __IPropertySetterInterceptor(builder);
            var propertyInterceptionInfo   = new __PropertyInterceptionInfo(builder);

            var properties = builder
                             .FindPropertiesByAttributes(attributes)
                             .GroupBy(x => x.Property)
                             .Select(x => new PropertyBuilderInfo(x.Key, x.Select(y => new PropertyBuilderInfoItem(y, y.Property,
                                                                                                                   y.Attribute.Type.Implements(iPropertyGetterInterceptor.Type.Fullname) ? iPropertyGetterInterceptor : null,
                                                                                                                   y.Attribute.Type.Implements(iPropertySetterInterceptor.Type.Fullname) ? iPropertySetterInterceptor : null))))
                             .ToArray();

            foreach (var member in properties)
            {
                this.LogInfo($"Implementing interceptors in property {member.Property}");

                if (!member.Property.IsAutoProperty)
                {
                    this.LogError($"{member.Property.Name}: The current version of the property interceptor only supports auto-properties.");
                    continue;
                }

                var propertyField = member.Property.CreateField(propertyInterceptionInfo.Type, $"<{member.Property.Name}>p__propertyInfo");

                var actionObjectCtor = builder.Import(typeof(Action <object>).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                var propertySetter   = member.Property.DeclaringType.CreateMethod(member.Property.Modifiers.GetPrivate(), $"<{member.Property.Name}>m__setterMethod", builder.GetType(typeof(object)));

                CreatePropertySetterDelegate(builder, member, propertySetter);

                if (member.RequiresSyncRootField)
                {
                    foreach (var ctors in member.Property.DeclaringType.GetRelevantConstructors())
                    {
                        ctors.NewCode().Assign(member.SyncRoot).NewObj(builder.GetType(typeof(object)).Import().ParameterlessContructor).Insert(InsertionPosition.Beginning);
                    }
                }

                #region Getter implementation

                var indexer           = 0;
                var interceptorFields = member.InterceptorInfos.ToDictionary(x => x.Attribute.Identification,
                                                                             x => member.Property.DeclaringType.CreateField(x.Property.Modifiers.GetPrivate(), x.Attribute.Attribute.Type,
                                                                                                                            $"<{x.Property.Name}>_attrib{indexer++}_{x.Attribute.Identification}"));

                if (member.HasGetterInterception)
                {
                    AddPropertyGetterInterception(builder, propertyInterceptionInfo, member, propertyField, actionObjectCtor, propertySetter, interceptorFields);
                }

                #endregion Getter implementation

                #region Setter implementation

                if (member.HasSetterInterception)
                {
                    AddPropertySetterInterception(builder, propertyInterceptionInfo, member, propertyField, actionObjectCtor, propertySetter, interceptorFields);
                }

                #endregion Setter implementation

                // Also remove the compilergenerated attribute
                member.Property.Getter?.CustomAttributes.Remove(typeof(CompilerGeneratedAttribute));
                member.Property.Setter?.CustomAttributes.Remove(typeof(CompilerGeneratedAttribute));
            }

            stopwatch.Stop();
            this.LogInfo($"Implementing property interceptors took {stopwatch.Elapsed.TotalMilliseconds}ms");
        }
        private static void AddPropertySetterInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var syncRoot = new __ISyncRoot();
            var legalSetterInterceptors = member.InterceptorInfos.Where(x => x.InterfaceSetter != null).ToArray();

            member.Property.Setter
            .NewCode()
            .Context(x =>
            {
                if (member.HasInitializer)
                {
                    return;
                }

                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).IsNull().Then(y =>
                    {
                        y.Assign(field).NewObj(item.Attribute);

                        if (item.HasSyncRootInterface)
                        {
                            y.Load(field).As(syncRoot.ToBuilderType.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }

                        ImplementAssignMethodAttribute(builder, legalSetterInterceptors[i].AssignMethodAttributeInfos, field, y, false);
                    });
                    item.Attribute.Remove();
                }

                x.Load(propertyField).IsNull().Then(y =>
                                                    y.Assign(propertyField)
                                                    .NewObj(propertyInterceptionInfo.Ctor,
                                                            member.Property.Getter,
                                                            member.Property.Setter,
                                                            member.Property.Name,
                                                            member.Property.ReturnType,
                                                            Crumb.This,
                                                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                                                            propertySetter == null ? null : y.NewCode().NewObj(actionObjectCtor, propertySetter)));
            })
            .Try(x =>
            {
                if (member.Property.BackingField == null)
                {
                    var oldvalue = member.Property.Getter == null ? null : x.CreateVariable(member.Property.ReturnType);

                    if (oldvalue != null)
                    {
                        var getter = member.Property.Getter.Copy();
                        x.Call(getter.IsStatic ? null : Crumb.This, getter).StoreLocal(oldvalue);
                    }

                    for (int i = 0; i < legalSetterInterceptors.Length; i++)
                    {
                        var item  = legalSetterInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(item.InterfaceSetter.OnSet, propertyField, oldvalue, Crumb.GetParameter(0));

                        x.IsFalse().Then(y => y.OriginalBodyNewMethod());
                    }
                }
                else
                {
                    for (int i = 0; i < legalSetterInterceptors.Length; i++)
                    {
                        var item  = legalSetterInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(item.InterfaceSetter.OnSet, propertyField, member.Property.BackingField, Crumb.GetParameter(0));

                        x.IsFalse().Then(y => y.OriginalBody());
                    }
                }
            })
            .Catch(typeof(Exception), x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(legalSetterInterceptors[i].InterfaceSetter.OnException, x.Exception);
                }

                x.Rethrow();
            })
            .Finally(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(legalSetterInterceptors[i].InterfaceSetter.OnExit);
                }
            })
            .EndTry()
            .Return()
            .Replace();
        }
        private void InterceptProperties(Builder builder, IEnumerable <BuilderType> attributes)
        {
            if (!attributes.Any())
            {
                return;
            }

            var stopwatch = Stopwatch.StartNew();

            var iPropertyInterceptorInitialize = new __IPropertyInterceptorInitialize(builder);
            var iPropertyGetterInterceptor     = new __IPropertyGetterInterceptor(builder);
            var iPropertySetterInterceptor     = new __IPropertySetterInterceptor(builder);
            var propertyInterceptionInfo       = new __PropertyInterceptionInfo(builder);

            var properties = builder
                             .FindPropertiesByAttributes(attributes)
                             .GroupBy(x => x.Property)
                             .Select(x => new PropertyBuilderInfo(x.Key, x.Select(y => new PropertyBuilderInfoItem(y, y.Property,
                                                                                                                   y.Attribute.Type.Implements(iPropertyGetterInterceptor.Type.Fullname) ? iPropertyGetterInterceptor : null,
                                                                                                                   y.Attribute.Type.Implements(iPropertySetterInterceptor.Type.Fullname) ? iPropertySetterInterceptor : null,
                                                                                                                   y.Attribute.Type.Implements(iPropertyInterceptorInitialize.Type.Fullname) ? iPropertyInterceptorInitialize : null))))
                             .ToArray();

            foreach (var member in properties)
            {
                this.Log($"Implementing interceptors in property {member.Property}");

                if (member.Property.BackingField == null)
                {
                    this.Log(LogTypes.Error, member.Property, "Unable to detect the backing field of property: " + member.Property);
                    continue;
                }

                var propertyField = member.Property.CreateField(propertyInterceptionInfo.Type, $"<{member.Property.Name}>p__propertyInfo");

                var actionObjectCtor = builder.Import(typeof(Action <object>).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                var propertySetter   = member.Property.DeclaringType.CreateMethod(member.Property.Modifiers.GetPrivate(), $"<{member.Property.Name}>m__setterMethod", builder.GetType(typeof(object)));

                CreatePropertySetterDelegate(builder, member, propertySetter);

                var indexer           = 0;
                var interceptorFields = member.InterceptorInfos.ToDictionary(x => x.Attribute.Identification,
                                                                             x => member.Property.DeclaringType.CreateField(x.Property.Modifiers.GetPrivate(), x.Attribute.Attribute.Type,
                                                                                                                            $"<{x.Property.Name}>_attrib{indexer++}_{x.Attribute.Identification}"));

                if (member.HasInitializer)
                {
                    AddPropertyInitializeInterception(builder, propertyInterceptionInfo, member, propertyField, actionObjectCtor, propertySetter, interceptorFields);
                }

                if (member.HasGetterInterception)
                {
                    AddPropertyGetterInterception(builder, propertyInterceptionInfo, member, propertyField, actionObjectCtor, propertySetter, interceptorFields);
                }

                if (member.HasSetterInterception)
                {
                    AddPropertySetterInterception(builder, propertyInterceptionInfo, member, propertyField, actionObjectCtor, propertySetter, interceptorFields);
                }

                // Do this at the end to ensure that syncroot init is always on the top
                if (member.RequiresSyncRootField)
                {
                    if (member.SyncRoot.IsStatic)
                    {
                        member.Property.DeclaringType.CreateStaticConstructor().NewCode()
                        .Assign(member.SyncRoot).NewObj(builder.GetType(typeof(object)).Import().ParameterlessContructor)
                        .Insert(InsertionPosition.Beginning);
                    }
                    else
                    {
                        foreach (var ctors in member.Property.DeclaringType.GetRelevantConstructors().Where(x => x.Name == ".ctor"))
                        {
                            ctors.NewCode().Assign(member.SyncRoot).NewObj(builder.GetType(typeof(object)).Import().ParameterlessContructor).Insert(InsertionPosition.Beginning);
                        }
                    }
                }

                // Also remove the compilergenerated attribute
                member.Property.Getter?.CustomAttributes.Remove(typeof(CompilerGeneratedAttribute));
                member.Property.Setter?.CustomAttributes.Remove(typeof(CompilerGeneratedAttribute));
            }

            stopwatch.Stop();
            this.Log($"Implementing property interceptors took {stopwatch.Elapsed.TotalMilliseconds}ms");
        }