1 // Copyright 2004-2008 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
.Builder
.CodeGenerators
19 using System
.Reflection
;
20 using System
.Runtime
.Serialization
;
21 using System
.Collections
;
22 using System
.Collections
.Specialized
;
23 using System
.Threading
;
25 using Castle
.DynamicProxy
.Builder
.CodeBuilder
;
26 using Castle
.DynamicProxy
.Builder
.CodeBuilder
.SimpleAST
;
27 using Castle
.DynamicProxy
.Builder
.CodeBuilder
.Utils
;
30 /// Summary description for ClassProxyGenerator.
33 public class ClassProxyGenerator
: BaseCodeGenerator
35 private bool _delegateToBaseGetObjectData
;
37 protected ConstructorInfo _serializationConstructor
;
39 public ClassProxyGenerator(ModuleScope scope
) : base(scope
)
43 public ClassProxyGenerator(ModuleScope scope
, GeneratorContext context
) : base(scope
, context
)
47 protected override Type InvocationType
49 get { return Context.SameClassInvocation; }
52 protected override String
GenerateTypeName(Type type
, Type
[] interfaces
)
54 StringBuilder sb
= new StringBuilder();
55 foreach (Type inter
in interfaces
)
58 sb
.Append(GetTypeName(inter
));
60 return String
.Format("CProxyType{0}{3}{1}{2}", GetTypeName(type
), sb
.ToString(), interfaces
.Length
, NormalizeNamespaceName(type
.Namespace
));
64 /// Generates one public constructor receiving
65 /// the <see cref="IInterceptor"/> instance and instantiating a hashtable
67 protected virtual EasyConstructor
GenerateConstructor( ConstructorInfo baseConstructor
)
69 ArrayList arguments
= new ArrayList();
71 ArgumentReference arg1
= new ArgumentReference( Context
.Interceptor
);
72 ArgumentReference arg2
= new ArgumentReference( typeof(object[]) );
74 arguments
.Add( arg1
);
76 ParameterInfo
[] parameters
= baseConstructor
.GetParameters();
78 if (Context
.HasMixins
)
80 arguments
.Add( arg2
);
83 ArgumentReference
[] originalArguments
=
84 ArgumentsUtil
.ConvertToArgumentReference(parameters
);
86 arguments
.AddRange(originalArguments
);
88 EasyConstructor constructor
= MainTypeBuilder
.CreateConstructor(
89 (ArgumentReference
[]) arguments
.ToArray( typeof(ArgumentReference
) ) );
91 GenerateConstructorCode(constructor
.CodeBuilder
, arg1
, SelfReference
.Self
, arg2
);
93 constructor
.CodeBuilder
.InvokeBaseConstructor( baseConstructor
, originalArguments
);
95 constructor
.CodeBuilder
.AddStatement( new ReturnStatement() );
100 protected void GenerateSerializationConstructor()
102 ArgumentReference arg1
= new ArgumentReference( typeof(SerializationInfo
) );
103 ArgumentReference arg2
= new ArgumentReference( typeof(StreamingContext
) );
105 EasyConstructor constr
= MainTypeBuilder
.CreateConstructor( arg1
, arg2
);
107 constr
.CodeBuilder
.AddStatement( new ExpressionStatement(
108 new ConstructorInvocationExpression( _serializationConstructor
,
109 arg1
.ToExpression(), arg2
.ToExpression() )) );
111 Type
[] object_arg
= new Type
[] { typeof (String), typeof(Type) }
;
112 MethodInfo getValueMethod
= typeof (SerializationInfo
).GetMethod("GetValue", object_arg
);
114 VirtualMethodInvocationExpression getInterceptorInvocation
=
115 new VirtualMethodInvocationExpression(arg1
, getValueMethod
,
116 new FixedReference("__interceptor").ToExpression(),
117 new TypeTokenExpression( Context
.Interceptor
) );
119 VirtualMethodInvocationExpression getMixinsInvocation
=
120 new VirtualMethodInvocationExpression(arg1
, getValueMethod
,
121 new FixedReference("__mixins").ToExpression(),
122 new TypeTokenExpression( typeof(object[]) ) );
124 constr
.CodeBuilder
.AddStatement( new AssignStatement(
125 InterceptorField
, getInterceptorInvocation
) );
127 constr
.CodeBuilder
.AddStatement( new AssignStatement(
128 CacheField
, new NewInstanceExpression(
129 typeof(HybridDictionary
).GetConstructor( new Type
[0] )) ) );
131 constr
.CodeBuilder
.AddStatement( new AssignStatement(
133 getMixinsInvocation
) );
135 // Initialize the delegate fields
136 foreach(CallableField field
in _cachedFields
)
138 field
.WriteInitialization(constr
.CodeBuilder
, SelfReference
.Self
, MixinField
);
141 constr
.CodeBuilder
.AddStatement( new ReturnStatement() );
144 protected override void CustomizeGetObjectData(AbstractCodeBuilder codebuilder
,
145 ArgumentReference arg1
, ArgumentReference arg2
)
147 Type
[] key_and_object
= new Type
[] {typeof (String), typeof (Object)}
;
148 Type
[] key_and_bool
= new Type
[] {typeof (String), typeof (bool)}
;
149 MethodInfo addValueMethod
= typeof (SerializationInfo
).GetMethod("AddValue", key_and_object
);
150 MethodInfo addValueBoolMethod
= typeof (SerializationInfo
).GetMethod("AddValue", key_and_bool
);
152 codebuilder
.AddStatement( new ExpressionStatement(
153 new VirtualMethodInvocationExpression(arg1
, addValueBoolMethod
,
154 new FixedReference("__delegateToBase").ToExpression(),
155 new FixedReference( _delegateToBaseGetObjectData
? 1 : 0 ).ToExpression() ) ) );
157 if (_delegateToBaseGetObjectData
)
159 MethodInfo baseGetObjectData
= _baseType
.GetMethod("GetObjectData",
160 new Type
[] { typeof(SerializationInfo), typeof(StreamingContext) }
);
162 codebuilder
.AddStatement( new ExpressionStatement(
163 new MethodInvocationExpression( baseGetObjectData
,
164 arg1
.ToExpression(), arg2
.ToExpression() )) );
168 LocalReference members_ref
= codebuilder
.DeclareLocal( typeof(MemberInfo
[]) );
169 LocalReference data_ref
= codebuilder
.DeclareLocal( typeof(object[]) );
171 MethodInfo getSerMembers
= typeof(FormatterServices
).GetMethod("GetSerializableMembers",
172 new Type
[] { typeof(Type) }
);
173 MethodInfo getObjData
= typeof(FormatterServices
).GetMethod("GetObjectData",
174 new Type
[] { typeof(object), typeof(MemberInfo[]) }
);
176 codebuilder
.AddStatement( new AssignStatement( members_ref
,
177 new MethodInvocationExpression( null, getSerMembers
,
178 new TypeTokenExpression( _baseType
) )) );
180 codebuilder
.AddStatement( new AssignStatement( data_ref
,
181 new MethodInvocationExpression( null, getObjData
,
182 SelfReference
.Self
.ToExpression(), members_ref
.ToExpression() )) );
184 codebuilder
.AddStatement( new ExpressionStatement(
185 new VirtualMethodInvocationExpression(arg1
, addValueMethod
,
186 new FixedReference("__data").ToExpression(),
187 data_ref
.ToExpression() ) ) );
191 public virtual Type
GenerateCode(Type baseClass
)
193 return GenerateCode(baseClass
, new Type
[0]);
196 public virtual Type
GenerateCode(Type baseClass
, Type
[] interfaces
)
198 if (baseClass
.IsSerializable
)
200 _delegateToBaseGetObjectData
= VerifyIfBaseImplementsGetObjectData(baseClass
);
201 interfaces
= AddISerializable( interfaces
);
204 ReaderWriterLock rwlock
= ModuleScope
.RWLock
;
206 rwlock
.AcquireReaderLock(-1);
208 Type cacheType
= GetFromCache(baseClass
, interfaces
);
210 if (cacheType
!= null)
212 rwlock
.ReleaseReaderLock();
217 rwlock
.UpgradeToWriterLock(-1);
221 cacheType
= GetFromCache(baseClass
, interfaces
);
223 if (cacheType
!= null)
228 CreateTypeBuilder( GenerateTypeName(baseClass
, interfaces
), baseClass
, interfaces
);
231 if (baseClass
.IsSerializable
)
233 ImplementGetObjectData( interfaces
);
236 ImplementCacheInvocationCache();
237 GenerateTypeImplementation( baseClass
, true );
238 GenerateInterfaceImplementation(interfaces
);
239 GenerateConstructors(baseClass
);
241 if (_delegateToBaseGetObjectData
)
243 GenerateSerializationConstructor();
250 rwlock
.ReleaseWriterLock();
254 public virtual Type
GenerateCustomCode(Type baseClass
, Type
[] interfaces
)
256 if (!Context
.HasMixins
)
258 return GenerateCode(baseClass
);
261 _mixins
= Context
.MixinsAsArray();
262 Type
[] mixinInterfaces
= InspectAndRegisterInterfaces( _mixins
);
263 interfaces
= Join(interfaces
, mixinInterfaces
);
265 return GenerateCode(baseClass
, mixinInterfaces
);
268 protected virtual void GenerateConstructors(Type baseClass
)
270 ConstructorInfo
[] constructors
=
271 baseClass
.GetConstructors( BindingFlags
.Instance
|BindingFlags
.Public
|BindingFlags
.NonPublic
);
273 foreach(ConstructorInfo constructor
in constructors
)
275 if (constructor
.IsPrivate
)
279 if (constructor
.IsAssembly
&& !IsInternalToDynamicProxy(baseClass
.Assembly
))
283 GenerateConstructor(constructor
);
287 protected bool VerifyIfBaseImplementsGetObjectData(Type baseType
)
289 // If base type implements ISerializable, we have to make sure
290 // the GetObjectData is marked as virtual
292 if (typeof(ISerializable
).IsAssignableFrom(baseType
))
294 MethodInfo getObjectDataMethod
= baseType
.GetMethod("GetObjectData",
295 new Type
[] { typeof(SerializationInfo), typeof(StreamingContext) }
);
297 if (getObjectDataMethod
==null)//explicit interface implementation
302 if (!getObjectDataMethod
.IsVirtual
|| getObjectDataMethod
.IsFinal
)
304 String message
= String
.Format("The type {0} implements ISerializable, but GetObjectData is not marked as virtual",
306 throw new ProxyGenerationException(message
);
309 Context
.AddMethodToSkip(getObjectDataMethod
);
311 _serializationConstructor
= baseType
.GetConstructor(
312 BindingFlags
.Instance
|BindingFlags
.Public
|BindingFlags
.NonPublic
,
314 new Type
[] { typeof(SerializationInfo), typeof(StreamingContext) }
,
317 if (_serializationConstructor
== null)
319 String message
= String
.Format("The type {0} implements ISerializable, but failed to provide a deserialization constructor",
321 throw new ProxyGenerationException(message
);
329 protected void SkipDefaultInterfaceImplementation(Type
[] interfaces
)
331 foreach( Type inter
in interfaces
)
333 Context
.AddInterfaceToSkip(inter
);
337 protected Type
[] Join(Type
[] interfaces
, Type
[] mixinInterfaces
)
339 if (interfaces
== null) interfaces
= new Type
[0];
340 if (mixinInterfaces
== null) mixinInterfaces
= new Type
[0];
341 Type
[] union
= new Type
[ interfaces
.Length
+ mixinInterfaces
.Length
];
342 Array
.Copy( interfaces
, 0, union
, 0, interfaces
.Length
);
343 Array
.Copy( mixinInterfaces
, 0, union
, interfaces
.Length
, mixinInterfaces
.Length
);