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 using System
.Collections
.Generic
;
17 namespace Castle
.DynamicProxy
.Generators
20 using System
.Collections
;
22 using System
.Collections
.Generic
;
24 using System
.Reflection
;
25 using System
.Reflection
.Emit
;
26 using System
.Threading
;
27 using System
.Xml
.Serialization
;
28 using Castle
.Core
.Interceptor
;
29 using Castle
.DynamicProxy
.Generators
.Emitters
;
30 using Castle
.DynamicProxy
.Generators
.Emitters
.SimpleAST
;
31 using System
.Collections
.Specialized
;
32 using System
.Runtime
.Serialization
;
33 using Castle
.DynamicProxy
.Generators
.Emitters
.CodeBuilders
;
34 using Castle
.DynamicProxy
.Serialization
;
40 public class ClassProxyGenerator
: BaseProxyGenerator
42 bool delegateToBaseGetObjectData
= false;
44 public ClassProxyGenerator(ModuleScope scope
, Type targetType
)
45 : base(scope
, targetType
)
47 CheckNotGenericTypeDefinition (targetType
, "targetType");
50 public Type
GenerateCode(Type
[] interfaces
, ProxyGenerationOptions options
)
52 CheckNotGenericTypeDefinitions (interfaces
, "interfaces");
55 ReaderWriterLock rwlock
= Scope
.RWLock
;
57 rwlock
.AcquireReaderLock(-1);
59 CacheKey cacheKey
= new CacheKey(targetType
, interfaces
, options
);
61 Type cacheType
= GetFromCache(cacheKey
);
63 if (cacheType
!= null)
65 rwlock
.ReleaseReaderLock();
70 rwlock
.UpgradeToWriterLock(-1);
74 cacheType
= GetFromCache(cacheKey
);
76 if (cacheType
!= null)
81 generationHook
= options
.Hook
;
83 String newName
= targetType
.Name
+ "Proxy" + Guid
.NewGuid().ToString("N");
85 // Add Interfaces that the proxy implements
87 ArrayList interfaceList
= new ArrayList();
89 if (interfaces
!= null)
91 interfaceList
.AddRange(interfaces
);
94 AddMixinInterfaces(options
, interfaceList
);
96 AddDefaultInterfaces(interfaceList
);
97 if (targetType
.IsSerializable
)
99 delegateToBaseGetObjectData
= VerifyIfBaseImplementsGetObjectData(targetType
);
100 if (!interfaceList
.Contains(typeof(ISerializable
)))
101 interfaceList
.Add(typeof(ISerializable
));
104 ClassEmitter emitter
= BuildClassEmitter(newName
, targetType
, interfaceList
);
105 emitter
.DefineCustomAttribute(new XmlIncludeAttribute(targetType
));
109 ReplicateNonInheritableAttributes(targetType
, emitter
);
111 // Fields generations
113 FieldReference interceptorsField
=
114 emitter
.CreateField("__interceptors", typeof(IInterceptor
[]));
116 // Implement builtin Interfaces
117 ImplementProxyTargetAccessor(targetType
, emitter
,interceptorsField
);
120 emitter
.DefineCustomAttributeFor(interceptorsField
, new XmlIgnoreAttribute());
124 PropertyToGenerate
[] propsToGenerate
;
125 EventToGenerate
[] eventToGenerates
;
126 MethodInfo
[] methods
= CollectMethodsAndProperties(emitter
, targetType
, out propsToGenerate
, out eventToGenerates
);
128 methods
= RegisterMixinMethodsAndProperties(emitter
, options
, methods
, ref propsToGenerate
, ref eventToGenerates
);
130 options
.Hook
.MethodsInspected();
134 ConstructorEmitter typeInitializer
= GenerateStaticConstructor(emitter
);
136 FieldReference
[] mixinFields
= AddMixinFields(options
, emitter
);
138 List
<FieldReference
> fields
= new List
<FieldReference
>(mixinFields
);
139 fields
.Add(interceptorsField
);
140 FieldReference
[] ctorArgs
= fields
.ToArray();
142 CreateInitializeCacheMethodBody(targetType
, methods
, emitter
, typeInitializer
);
143 GenerateConstructors(emitter
, targetType
, ctorArgs
);
144 GenerateParameterlessConstructor(emitter
, targetType
, interceptorsField
);
146 if (delegateToBaseGetObjectData
)
148 GenerateSerializationConstructor(emitter
, interceptorsField
, delegateToBaseGetObjectData
);
151 // Implement interfaces
152 if (interfaces
!= null && interfaces
.Length
!= 0)
154 foreach (Type inter
in interfaces
)
156 ImplementBlankInterface(targetType
, inter
, emitter
, interceptorsField
, typeInitializer
);
160 // Create callback methods
162 Dictionary
<MethodInfo
, MethodBuilder
> method2Callback
= new Dictionary
<MethodInfo
, MethodBuilder
>();
164 foreach (MethodInfo method
in methods
)
166 method2Callback
[method
] = CreateCallbackMethod(emitter
, method
, method
);
169 // Create invocation types
171 Dictionary
<MethodInfo
, NestedClassEmitter
> method2Invocation
= new Dictionary
<MethodInfo
, NestedClassEmitter
>();
173 foreach (MethodInfo method
in methods
)
175 MethodBuilder callbackMethod
= method2Callback
[method
];
177 method2Invocation
[method
] = BuildInvocationNestedType(emitter
, targetType
,
178 GetMethodTargetType(method
),
179 method
, callbackMethod
,
180 ConstructorVersion
.WithoutTargetMethod
);
183 // Create methods overrides
185 Dictionary
<MethodInfo
, MethodEmitter
> method2Emitter
= new Dictionary
<MethodInfo
, MethodEmitter
>();
187 foreach (MethodInfo method
in methods
)
189 if (method
.IsSpecialName
&& (method
.Name
.StartsWith("get_") || method
.Name
.StartsWith("set_")) || methodsToSkip
.Contains(method
))
194 NestedClassEmitter nestedClass
= method2Invocation
[method
];
196 Reference targetRef
= GetTargetRef(method
, mixinFields
, SelfReference
.Self
);
197 MethodEmitter newProxiedMethod
= CreateProxiedMethod(
198 targetType
, method
, emitter
, nestedClass
, interceptorsField
, targetRef
,
199 ConstructorVersion
.WithoutTargetMethod
, null);
201 ReplicateNonInheritableAttributes(method
, newProxiedMethod
);
203 method2Emitter
[method
] = newProxiedMethod
;
206 foreach (PropertyToGenerate propToGen
in propsToGenerate
)
208 if (propToGen
.CanRead
)
210 NestedClassEmitter nestedClass
= method2Invocation
[propToGen
.GetMethod
];
212 MethodAttributes atts
= ObtainMethodAttributes(propToGen
.GetMethod
);
214 MethodEmitter getEmitter
= propToGen
.Emitter
.CreateGetMethod(atts
);
216 Reference targetRef
= GetTargetRef(propToGen
.GetMethod
, mixinFields
, SelfReference
.Self
);
218 ImplementProxiedMethod(targetType
, getEmitter
,
219 propToGen
.GetMethod
, emitter
,
220 nestedClass
, interceptorsField
, targetRef
,
221 ConstructorVersion
.WithoutTargetMethod
, null);
223 ReplicateNonInheritableAttributes(propToGen
.GetMethod
, getEmitter
);
226 if (propToGen
.CanWrite
)
228 NestedClassEmitter nestedClass
= method2Invocation
[propToGen
.SetMethod
];
230 MethodAttributes atts
= ObtainMethodAttributes(propToGen
.SetMethod
);
232 MethodEmitter setEmitter
= propToGen
.Emitter
.CreateSetMethod(atts
);
234 Reference targetRef
= GetTargetRef(propToGen
.SetMethod
, mixinFields
, SelfReference
.Self
);
236 ImplementProxiedMethod(targetType
, setEmitter
,
237 propToGen
.SetMethod
, emitter
,
238 nestedClass
, interceptorsField
, targetRef
,
239 ConstructorVersion
.WithoutTargetMethod
, null);
241 ReplicateNonInheritableAttributes(propToGen
.SetMethod
, setEmitter
);
245 foreach (EventToGenerate eventToGenerate
in eventToGenerates
)
248 NestedClassEmitter add_nestedClass
= method2Invocation
[eventToGenerate
.AddMethod
];
250 MethodAttributes add_atts
= ObtainMethodAttributes(eventToGenerate
.AddMethod
);
252 MethodEmitter addEmitter
= eventToGenerate
.Emitter
.CreateAddMethod(add_atts
);
254 Reference targetRef
= GetTargetRef(eventToGenerate
.AddMethod
, mixinFields
, SelfReference
.Self
);
256 ImplementProxiedMethod(targetType
, addEmitter
,
257 eventToGenerate
.AddMethod
, emitter
,
258 add_nestedClass
, interceptorsField
, targetRef
,
259 ConstructorVersion
.WithoutTargetMethod
, null);
261 ReplicateNonInheritableAttributes(eventToGenerate
.AddMethod
, addEmitter
);
263 NestedClassEmitter remove_nestedClass
= method2Invocation
[eventToGenerate
.RemoveMethod
];
265 MethodAttributes remove_atts
= ObtainMethodAttributes(eventToGenerate
.RemoveMethod
);
267 MethodEmitter removeEmitter
= eventToGenerate
.Emitter
.CreateRemoveMethod(remove_atts
);
269 ImplementProxiedMethod(targetType
, removeEmitter
,
270 eventToGenerate
.RemoveMethod
, emitter
,
271 remove_nestedClass
, interceptorsField
, targetRef
,
272 ConstructorVersion
.WithoutTargetMethod
, null);
274 ReplicateNonInheritableAttributes(eventToGenerate
.RemoveMethod
, removeEmitter
);
279 ImplementGetObjectData(emitter
, interceptorsField
, interfaces
);
281 // Complete type initializer code body
283 CompleteInitCacheMethod(typeInitializer
.CodeBuilder
);
287 type
= emitter
.BuildType();
289 AddToCache(cacheKey
, type
);
293 rwlock
.ReleaseWriterLock();
296 Scope
.SaveAssembly();
302 protected override Reference
GetProxyTargetReference()
304 return SelfReference
.Self
;
307 protected override bool CanOnlyProxyVirtual()
312 protected void GenerateSerializationConstructor(ClassEmitter emitter
, FieldReference interceptorField
, bool delegateToBaseGetObjectData
)
314 ArgumentReference arg1
= new ArgumentReference(typeof(SerializationInfo
));
315 ArgumentReference arg2
= new ArgumentReference(typeof(StreamingContext
));
317 ConstructorEmitter constr
= emitter
.CreateConstructor(arg1
, arg2
);
319 constr
.CodeBuilder
.AddStatement(
320 new ConstructorInvocationStatement(serializationConstructor
,
321 arg1
.ToExpression(), arg2
.ToExpression()));
323 Type
[] object_arg
= new Type
[] { typeof(String), typeof(Type) }
;
324 MethodInfo getValueMethod
= typeof(SerializationInfo
).GetMethod("GetValue", object_arg
);
326 MethodInvocationExpression getInterceptorInvocation
=
327 new MethodInvocationExpression(arg1
, getValueMethod
,
328 new ConstReference("__interceptors").ToExpression(),
329 new TypeTokenExpression(typeof(IInterceptor
[])));
331 constr
.CodeBuilder
.AddStatement(new AssignStatement(
332 interceptorField
, getInterceptorInvocation
));
334 constr
.CodeBuilder
.AddStatement(new ReturnStatement());
337 protected override void CustomizeGetObjectData(AbstractCodeBuilder codebuilder
,
338 ArgumentReference arg1
, ArgumentReference arg2
)
340 codebuilder
.AddStatement (new ExpressionStatement (new MethodInvocationExpression (null,
341 typeof (ProxySerializer
).GetMethod ("SerializeClassProxyData"), arg1
.ToExpression (),
342 new ConstReference (delegateToBaseGetObjectData
).ToExpression (), new TypeTokenExpression (targetType
),
343 SelfReference
.Self
.ToExpression())));
345 if (delegateToBaseGetObjectData
)
347 MethodInfo baseGetObjectData
= targetType
.GetMethod("GetObjectData",
348 new Type
[] { typeof(SerializationInfo), typeof(StreamingContext) }
);
350 codebuilder
.AddStatement( new ExpressionStatement(
351 new MethodInvocationExpression( baseGetObjectData
,
352 arg1
.ToExpression(), arg2
.ToExpression() )) );