1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
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
;
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");
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();
62 rwlock
.UpgradeToWriterLock(-1);
66 cacheType
= GetFromCache(cacheKey
);
68 if (cacheType
!= null)
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
));
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());
117 PropertyToGenerate
[] propsToGenerate
;
118 EventToGenerate
[] eventToGenerates
;
119 MethodInfo
[] methods
= CollectMethodsAndProperties(emitter
, targetType
, out propsToGenerate
, out eventToGenerates
);
121 options
.Hook
.MethodsInspected();
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
,
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
))
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
);
266 type
= emitter
.BuildType();
267 InitializeStaticFields (type
);
269 AddToCache(cacheKey
, type
);
273 rwlock
.ReleaseWriterLock();
276 Scope
.SaveAssembly();
281 protected override Reference
GetProxyTargetReference()
283 return SelfReference
.Self
;
286 protected override bool CanOnlyProxyVirtual()
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(
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).
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())));
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())));