PageRenderTime 83ms CodeModel.GetById 40ms app.highlight 10ms RepoModel.GetById 30ms app.codeStats 0ms

/src/LinFu.AOP/Extensions/FieldInterceptionExtensions.cs

http://github.com/philiplaureano/LinFu
C# | 180 lines | 109 code | 20 blank | 51 comment | 3 complexity | 759fa863e8db0ef727ee863d1edd504b MD5 | raw file
  1using System;
  2using System.Linq;
  3using LinFu.AOP.Cecil.Interfaces;
  4using LinFu.AOP.Interfaces;
  5using LinFu.Reflection.Emit;
  6using Mono.Cecil;
  7
  8namespace LinFu.AOP.Cecil.Extensions
  9{
 10    /// <summary>
 11    ///     Represents an extension class that adds field interception support to a given type.
 12    /// </summary>
 13    public static class FieldInterceptionExtensions
 14    {
 15        /// <summary>
 16        ///     Adds field interception support to the target type.
 17        /// </summary>
 18        /// <param name="targetType">The type that will be modified.</param>
 19        public static void InterceptAllFields(this AssemblyDefinition targetType)
 20        {
 21            var methodFilter = GetMethodFilter();
 22            targetType.InterceptFields(methodFilter, f => true);
 23        }
 24
 25        /// <summary>
 26        ///     Adds field interception support intercepting all instance fields on the target type.
 27        /// </summary>
 28        /// <param name="targetType">The type that will be modified.</param>
 29        public static void InterceptAllInstanceFields(this AssemblyDefinition targetType)
 30        {
 31            var methodFilter = GetMethodFilter();
 32            var fieldFilter = GetFieldFilter(f => !f.IsStatic);
 33
 34            targetType.InterceptFields(methodFilter, fieldFilter);
 35        }
 36
 37        /// <summary>
 38        ///     Adds field interception support intercepting all static fields on the target type.
 39        /// </summary>
 40        /// <param name="targetType">The type that will be modified.</param>
 41        public static void InterceptAllStaticFields(this AssemblyDefinition targetType)
 42        {
 43            var methodFilter = GetMethodFilter();
 44            var fieldFilter = GetFieldFilter(f => f.IsStatic);
 45
 46            targetType.InterceptFields(methodFilter, fieldFilter);
 47        }
 48
 49        /// <summary>
 50        ///     Adds field interception support to the target type.
 51        /// </summary>
 52        /// <param name="targetType">The type that will be modified.</param>
 53        public static void InterceptAllFields(this TypeDefinition targetType)
 54        {
 55            var methodFilter = GetMethodFilter();
 56            targetType.InterceptFields(methodFilter, f => true);
 57        }
 58
 59        /// <summary>
 60        ///     Adds field interception support intercepting all instance fields on the target type.
 61        /// </summary>
 62        /// <param name="targetType">The type that will be modified.</param>
 63        public static void InterceptAllInstanceFields(this TypeDefinition targetType)
 64        {
 65            var methodFilter = GetMethodFilter();
 66            var fieldFilter = GetFieldFilter(f => !f.IsStatic);
 67
 68            targetType.InterceptFields(methodFilter, fieldFilter);
 69        }
 70
 71        /// <summary>
 72        ///     Adds field interception support intercepting all static fields on the target type.
 73        /// </summary>
 74        /// <param name="targetType">The type that will be modified.</param>
 75        public static void InterceptAllStaticFields(this TypeDefinition targetType)
 76        {
 77            var methodFilter = GetMethodFilter();
 78            var fieldFilter = GetFieldFilter(actualField => actualField.IsStatic);
 79
 80            targetType.InterceptFields(methodFilter, fieldFilter);
 81        }
 82
 83        /// <summary>
 84        ///     Adds field interception support to the target type.
 85        /// </summary>
 86        /// <param name="targetType">The type that will be modified.</param>
 87        /// <param name="methodFilter">
 88        ///     The filter that determines which methods on the target type will be modified to support
 89        ///     field interception.
 90        /// </param>
 91        /// <param name="fieldFilter">The filter that determines which fields should be intercepted.</param>
 92        public static void InterceptFields(this TypeDefinition targetType,
 93            Func<MethodReference, bool> methodFilter,
 94            Func<FieldReference, bool> fieldFilter)
 95        {
 96            var typeWeaver = new ImplementFieldInterceptionHostWeaver(t => true);
 97            var fieldWeaver = new InterceptFieldAccess(fieldFilter);
 98
 99            typeWeaver.Weave(targetType);
100            var targetMethods = targetType.Methods.Where(m => methodFilter(m)).ToArray();
101            foreach (var method in targetMethods)
102            {
103                fieldWeaver.Rewrite(method, method.GetILGenerator(), method.Body.Instructions.ToArray());
104            }
105        }
106
107        /// <summary>
108        ///     Adds field interception support to the target type.
109        /// </summary>
110        /// <param name="targetAssembly">The type that will be modified.</param>
111        /// <param name="hostTypeFilter">The filter that determines the host types to be modified.</param>
112        /// <param name="fieldFilter">The field filter that determines the fields that will be intercepted.</param>
113        public static void InterceptFields(this AssemblyDefinition targetAssembly, ITypeFilter hostTypeFilter,
114            IFieldFilter fieldFilter)
115        {
116            var typeWeaver = new ImplementFieldInterceptionHostWeaver(hostTypeFilter.ShouldWeave);
117            var fieldWeaver = new InterceptFieldAccess(fieldFilter);
118
119            var module = targetAssembly.MainModule;
120            var targetTypes = module.Types.Where(hostTypeFilter.ShouldWeave).ToArray();
121            foreach (var type in targetTypes)
122            {
123                typeWeaver.Weave(type);
124                foreach (var method in type.Methods.Where(m => m.HasBody))
125                {
126                    fieldWeaver.Rewrite(method, method.GetILGenerator(), method.Body.Instructions.ToArray());
127                }
128            }
129        }
130
131        /// <summary>
132        ///     Adds field interception support to the target type.
133        /// </summary>
134        /// <param name="targetAssembly">The type that will be modified.</param>
135        /// <param name="methodFilter">
136        ///     The filter that determines which methods on the target type will be modified to support
137        ///     field interception.
138        /// </param>
139        /// <param name="fieldFilter">The filter that determines which fields should be intercepted.</param>
140        public static void InterceptFields(this AssemblyDefinition targetAssembly,
141            Func<MethodReference, bool> methodFilter,
142            Func<FieldReference, bool> fieldFilter)
143        {
144            var typeWeaver = new ImplementFieldInterceptionHostWeaver(t => t.IsByReference && !t.IsValueType);
145            var fieldWeaver = new InterceptFieldAccess(fieldFilter);
146
147            var module = targetAssembly.MainModule;
148            var targetTypes = module.Types.Where(t => t.Methods.Any(m => methodFilter(m))).ToArray();
149            foreach (var type in targetTypes)
150            {
151                typeWeaver.Weave(type);
152                foreach (var method in type.Methods.Where(m => m.HasBody))
153                {
154                    fieldWeaver.Rewrite(method, method.GetILGenerator(), method.Body.Instructions.ToArray());
155                }
156            }
157        }
158
159        private static Func<MethodReference, bool> GetMethodFilter()
160        {
161            return m => true;
162        }
163
164        private static Func<FieldReference, bool> GetFieldFilter(Func<FieldDefinition, bool> fieldFilter)
165        {
166            return field =>
167            {
168                var actualField = field.Resolve();
169                var fieldType = actualField.FieldType;
170                var module = fieldType.Module;
171
172                var moduleName = module != null ? module.Name : string.Empty;
173                if (moduleName.StartsWith("LinFu.AOP"))
174                    return false;
175
176                return fieldFilter(actualField);
177            };
178        }
179    }
180}