Added container accessor to Castle.Core
[castle.git] / Tools / Castle.DynamicProxy2 / Castle.DynamicProxy / Generators / ClassProxyGenerator.cs
blobfe09c786c1b26a4b480b7291a61f7ed2520de861
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.DynamicProxy.Generators
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Reflection;
21 using System.Reflection.Emit;
22 using System.Runtime.Serialization;
23 using System.Threading;
24 using System.Xml.Serialization;
25 using Castle.Core.Interceptor;
26 using Castle.DynamicProxy.Generators.Emitters;
27 using Castle.DynamicProxy.Generators.Emitters.CodeBuilders;
28 using Castle.DynamicProxy.Generators.Emitters.SimpleAST;
30 /// <summary>
31 ///
32 /// </summary>
33 public class ClassProxyGenerator : BaseProxyGenerator
35 private bool delegateToBaseGetObjectData = false;
37 public ClassProxyGenerator(ModuleScope scope, Type targetType) : base(scope, targetType)
39 CheckNotGenericTypeDefinition(targetType, "targetType");
42 public Type GenerateCode(Type[] interfaces, ProxyGenerationOptions options)
44 CheckNotGenericTypeDefinitions(interfaces, "interfaces");
45 Type type;
47 ReaderWriterLock rwlock = Scope.RWLock;
49 rwlock.AcquireReaderLock(-1);
51 CacheKey cacheKey = new CacheKey(targetType, interfaces, options);
53 Type cacheType = GetFromCache(cacheKey);
55 if (cacheType != null)
57 rwlock.ReleaseReaderLock();
59 return cacheType;
62 rwlock.UpgradeToWriterLock(-1);
64 try
66 cacheType = GetFromCache(cacheKey);
68 if (cacheType != null)
70 return cacheType;
73 String newName = targetType.Name + "Proxy" + Guid.NewGuid().ToString("N");
75 // Add Interfaces that the proxy implements
77 ArrayList interfaceList = new ArrayList();
79 if (interfaces != null)
81 interfaceList.AddRange(interfaces);
84 AddDefaultInterfaces(interfaceList);
86 if (targetType.IsSerializable)
88 delegateToBaseGetObjectData = VerifyIfBaseImplementsGetObjectData(targetType);
90 if (!interfaceList.Contains(typeof(ISerializable)))
92 interfaceList.Add(typeof(ISerializable));
96 ClassEmitter emitter = BuildClassEmitter(newName, targetType, interfaceList);
97 SetGenerationOptions (options, emitter);
99 emitter.DefineCustomAttribute(new XmlIncludeAttribute(targetType));
101 // Custom attributes
103 ReplicateNonInheritableAttributes(targetType, emitter);
105 // Fields generations
107 FieldReference interceptorsField =
108 emitter.CreateField("__interceptors", typeof(IInterceptor[]));
110 // Implement builtin Interfaces
111 ImplementProxyTargetAccessor(targetType, emitter,interceptorsField);
113 emitter.DefineCustomAttributeFor(interceptorsField, new XmlIgnoreAttribute());
115 // Collect methods
117 PropertyToGenerate[] propsToGenerate;
118 EventToGenerate[] eventToGenerates;
119 MethodInfo[] methods = CollectMethodsAndProperties(emitter, targetType, out propsToGenerate, out eventToGenerates);
121 options.Hook.MethodsInspected();
123 // Constructor
125 ConstructorEmitter typeInitializer = GenerateStaticConstructor(emitter);
127 CreateInitializeCacheMethodBody(targetType, methods, emitter, typeInitializer);
128 GenerateConstructors(emitter, targetType, interceptorsField);
129 GenerateParameterlessConstructor(emitter, targetType, interceptorsField);
131 if (delegateToBaseGetObjectData)
133 GenerateSerializationConstructor(emitter, interceptorsField, delegateToBaseGetObjectData);
136 // Implement interfaces
138 if (interfaces != null && interfaces.Length != 0)
140 foreach(Type inter in interfaces)
142 ImplementBlankInterface(targetType, inter, emitter, interceptorsField, typeInitializer);
146 // Create callback methods
148 Dictionary<MethodInfo, MethodBuilder> method2Callback = new Dictionary<MethodInfo, MethodBuilder>();
150 foreach(MethodInfo method in methods)
152 method2Callback[method] = CreateCallbackMethod(emitter, method, method);
155 // Create invocation types
157 Dictionary<MethodInfo, NestedClassEmitter> method2Invocation = new Dictionary<MethodInfo, NestedClassEmitter>();
159 foreach(MethodInfo method in methods)
161 MethodBuilder callbackMethod = method2Callback[method];
163 method2Invocation[method] = BuildInvocationNestedType(emitter, targetType,
164 emitter.TypeBuilder,
165 method, callbackMethod,
166 ConstructorVersion.WithoutTargetMethod);
169 // Create methods overrides
171 Dictionary<MethodInfo, MethodEmitter> method2Emitter = new Dictionary<MethodInfo, MethodEmitter>();
173 foreach(MethodInfo method in methods)
175 if (method.IsSpecialName &&
176 (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ||
177 method.Name.StartsWith("add_") || method.Name.StartsWith("remove_")) ||
178 methodsToSkip.Contains(method))
180 continue;
183 NestedClassEmitter nestedClass = method2Invocation[method];
185 MethodEmitter newProxiedMethod = CreateProxiedMethod(
186 targetType, method, emitter, nestedClass, interceptorsField, SelfReference.Self,
187 ConstructorVersion.WithoutTargetMethod, null);
189 ReplicateNonInheritableAttributes(method, newProxiedMethod);
191 method2Emitter[method] = newProxiedMethod;
194 foreach(PropertyToGenerate propToGen in propsToGenerate)
196 if (propToGen.CanRead)
198 NestedClassEmitter nestedClass = method2Invocation[propToGen.GetMethod];
200 MethodAttributes atts = ObtainMethodAttributes(propToGen.GetMethod);
202 MethodEmitter getEmitter = propToGen.Emitter.CreateGetMethod(atts);
204 ImplementProxiedMethod(targetType, getEmitter,
205 propToGen.GetMethod, emitter,
206 nestedClass, interceptorsField, SelfReference.Self,
207 ConstructorVersion.WithoutTargetMethod, null);
209 ReplicateNonInheritableAttributes(propToGen.GetMethod, getEmitter);
212 if (propToGen.CanWrite)
214 NestedClassEmitter nestedClass = method2Invocation[propToGen.SetMethod];
216 MethodAttributes atts = ObtainMethodAttributes(propToGen.SetMethod);
218 MethodEmitter setEmitter = propToGen.Emitter.CreateSetMethod(atts);
220 ImplementProxiedMethod(targetType, setEmitter,
221 propToGen.SetMethod, emitter,
222 nestedClass, interceptorsField, SelfReference.Self,
223 ConstructorVersion.WithoutTargetMethod, null);
225 ReplicateNonInheritableAttributes(propToGen.SetMethod, setEmitter);
229 foreach(EventToGenerate eventToGenerate in eventToGenerates)
231 NestedClassEmitter add_nestedClass = method2Invocation[eventToGenerate.AddMethod];
233 MethodAttributes add_atts = ObtainMethodAttributes(eventToGenerate.AddMethod);
235 MethodEmitter addEmitter = eventToGenerate.Emitter.CreateAddMethod(add_atts);
237 ImplementProxiedMethod(targetType, addEmitter,
238 eventToGenerate.AddMethod, emitter,
239 add_nestedClass, interceptorsField, SelfReference.Self,
240 ConstructorVersion.WithoutTargetMethod, null);
242 ReplicateNonInheritableAttributes(eventToGenerate.AddMethod, addEmitter);
244 NestedClassEmitter remove_nestedClass = method2Invocation[eventToGenerate.RemoveMethod];
246 MethodAttributes remove_atts = ObtainMethodAttributes(eventToGenerate.RemoveMethod);
248 MethodEmitter removeEmitter = eventToGenerate.Emitter.CreateRemoveMethod(remove_atts);
250 ImplementProxiedMethod(targetType, removeEmitter,
251 eventToGenerate.RemoveMethod, emitter,
252 remove_nestedClass, interceptorsField, SelfReference.Self,
253 ConstructorVersion.WithoutTargetMethod, null);
255 ReplicateNonInheritableAttributes(eventToGenerate.RemoveMethod, removeEmitter);
258 ImplementGetObjectData(emitter, interceptorsField, interfaces);
260 // Complete type initializer code body
262 CompleteInitCacheMethod(typeInitializer.CodeBuilder);
264 // Build type
266 type = emitter.BuildType();
267 InitializeStaticFields (type);
269 AddToCache(cacheKey, type);
271 finally
273 rwlock.ReleaseWriterLock();
276 Scope.SaveAssembly();
278 return type;
281 protected override Reference GetProxyTargetReference()
283 return SelfReference.Self;
286 protected override bool CanOnlyProxyVirtual()
288 return true;
291 protected void GenerateSerializationConstructor(ClassEmitter emitter, FieldReference interceptorField,
292 bool delegateToBaseGetObjectData)
294 ArgumentReference arg1 = new ArgumentReference(typeof(SerializationInfo));
295 ArgumentReference arg2 = new ArgumentReference(typeof(StreamingContext));
297 ConstructorEmitter constr = emitter.CreateConstructor(arg1, arg2);
299 constr.CodeBuilder.AddStatement(
300 new ConstructorInvocationStatement(serializationConstructor,
301 arg1.ToExpression(), arg2.ToExpression()));
303 Type[] object_arg = new Type[] {typeof(String), typeof(Type)};
304 MethodInfo getValueMethod = typeof(SerializationInfo).GetMethod("GetValue", object_arg);
306 MethodInvocationExpression getInterceptorInvocation =
307 new MethodInvocationExpression(arg1, getValueMethod,
308 new ConstReference("__interceptors").ToExpression(),
309 new TypeTokenExpression(typeof(IInterceptor[])));
311 constr.CodeBuilder.AddStatement(new AssignStatement(
312 interceptorField,
313 new ConvertExpression(typeof(IInterceptor[]), typeof(object),
314 getInterceptorInvocation)));
316 constr.CodeBuilder.AddStatement(new ReturnStatement());
319 protected override void CustomizeGetObjectData(AbstractCodeBuilder codebuilder,
320 ArgumentReference arg1, ArgumentReference arg2)
322 Type[] key_and_object = new Type[] {typeof(String), typeof(Object)};
323 Type[] key_and_bool = new Type[] {typeof(String), typeof(bool)};
324 MethodInfo addValueMethod = typeof(SerializationInfo).GetMethod("AddValue", key_and_object);
325 MethodInfo addValueBoolMethod = typeof(SerializationInfo).GetMethod("AddValue", key_and_bool);
327 codebuilder.AddStatement(new ExpressionStatement(
328 new MethodInvocationExpression(arg1, addValueBoolMethod,
329 new ConstReference("__delegateToBase").ToExpression(),
330 new ConstReference(delegateToBaseGetObjectData ? 1 : 0).
331 ToExpression())));
333 if (delegateToBaseGetObjectData)
335 MethodInfo baseGetObjectData = targetType.GetMethod("GetObjectData",
336 new Type[] {typeof(SerializationInfo), typeof(StreamingContext)});
338 codebuilder.AddStatement(new ExpressionStatement(
339 new MethodInvocationExpression(baseGetObjectData,
340 arg1.ToExpression(), arg2.ToExpression())));
342 else
344 LocalReference members_ref = codebuilder.DeclareLocal(typeof(MemberInfo[]));
345 LocalReference data_ref = codebuilder.DeclareLocal(typeof(object[]));
347 MethodInfo getSerMembers = typeof(FormatterServices).GetMethod("GetSerializableMembers",
348 new Type[] {typeof(Type)});
349 MethodInfo getObjData = typeof(FormatterServices).GetMethod("GetObjectData",
350 new Type[] {typeof(object), typeof(MemberInfo[])});
352 codebuilder.AddStatement(new AssignStatement(members_ref,
353 new MethodInvocationExpression(null, getSerMembers,
354 new TypeTokenExpression(targetType))));
356 codebuilder.AddStatement(new AssignStatement(data_ref,
357 new MethodInvocationExpression(null, getObjData,
358 SelfReference.Self.ToExpression(),
359 members_ref.ToExpression())));
361 codebuilder.AddStatement(new ExpressionStatement(
362 new MethodInvocationExpression(arg1, addValueMethod,
363 new ConstReference("__data").ToExpression(),
364 data_ref.ToExpression())));