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"); }