Fixing an issue with output parameters that are of type IntPtr
[castle.git] / Tools / DynamicProxy / Castle.DynamicProxy / Builder / CodeGenerators / InterfaceProxyGenerator.cs
blobb4066a58594f8d922d6b77badeee2219c6d6ccda
1 // Copyright 2004-2008 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.Builder.CodeGenerators
17 using System;
18 using System.Text;
19 using System.Reflection;
20 using System.Runtime.Serialization;
21 using System.Threading;
22 using Castle.DynamicProxy.Builder.CodeBuilder;
23 using Castle.DynamicProxy.Builder.CodeBuilder.SimpleAST;
25 /// <summary>
26 /// Summary description for InterfaceProxyGenerator.
27 /// </summary>
28 [CLSCompliant(false)]
29 public class InterfaceProxyGenerator : BaseCodeGenerator
31 protected Type _targetType;
32 protected FieldReference _targetField;
34 public InterfaceProxyGenerator(ModuleScope scope) : base(scope)
38 public InterfaceProxyGenerator(ModuleScope scope, GeneratorContext context) : base(scope, context)
42 protected override Type InvocationType
44 get { return Context.InterfaceInvocation; }
47 protected override String GenerateTypeName(Type type, Type[] interfaces)
49 StringBuilder sb = new StringBuilder();
50 foreach(Type inter in interfaces)
52 sb.Append('_');
53 sb.Append(GetTypeName(inter));
55 return
56 String.Format("ProxyInterface{2}{0}{1}", GetTypeName(type), sb.ToString(), NormalizeNamespaceName(type.Namespace));
59 protected override void GenerateFields()
61 base.GenerateFields();
62 _targetField = MainTypeBuilder.CreateField("__target", typeof(object));
66 protected override MethodInfo GenerateCallbackMethodIfNecessary(MethodInfo method, Reference invocationTarget)
68 if (Context.HasMixins && _interface2mixinIndex.Contains(method.DeclaringType))
70 return method;
73 if (method.IsAbstract)
75 method = GetCorrectMethod(method);
78 return base.GenerateCallbackMethodIfNecessary(method, _targetField);
81 /// <summary>
82 /// From an interface method (abstract) look up
83 /// for a matching method on the target
84 /// </summary>
85 /// <param name="method"></param>
86 /// <returns></returns>
87 protected override MethodInfo GetCorrectMethod(MethodInfo method)
89 if (Context.HasMixins && _interface2mixinIndex.Contains(method.DeclaringType))
91 return method;
94 ParameterInfo[] paramsInfo = method.GetParameters();
95 Type[] argTypes = new Type[paramsInfo.Length];
97 for(int i = 0; i < argTypes.Length; i++)
99 argTypes[i] = paramsInfo[i].ParameterType;
102 MethodInfo newMethod = _targetType.GetMethod(method.Name, argTypes);
104 if (newMethod == null)
106 //System.Diagnostics.Trace.Write("Target class does not offer the method " + method.Name);
107 newMethod = method;
110 return newMethod;
113 /// <summary>
114 /// Generates one public constructor receiving
115 /// the <see cref="IInterceptor"/> instance and instantiating a HybridCollection
116 /// </summary>
117 protected override EasyConstructor GenerateConstructor()
119 ArgumentReference arg1 = new ArgumentReference(Context.Interceptor);
120 ArgumentReference arg2 = new ArgumentReference(typeof(object));
121 ArgumentReference arg3 = new ArgumentReference(typeof(object[]));
123 EasyConstructor constructor;
125 if (Context.HasMixins)
127 constructor = MainTypeBuilder.CreateConstructor(arg1, arg2, arg3);
129 else
131 constructor = MainTypeBuilder.CreateConstructor(arg1, arg2);
134 GenerateConstructorCode(constructor.CodeBuilder, arg1, SelfReference.Self, arg3);
136 constructor.CodeBuilder.InvokeBaseConstructor();
138 constructor.CodeBuilder.AddStatement(new AssignStatement(
139 _targetField, arg2.ToExpression()));
141 constructor.CodeBuilder.AddStatement(new ReturnStatement());
143 return constructor;
146 protected Type[] Join(Type[] interfaces, Type[] mixinInterfaces)
148 Type[] union = new Type[interfaces.Length + mixinInterfaces.Length];
149 Array.Copy(interfaces, 0, union, 0, interfaces.Length);
150 Array.Copy(mixinInterfaces, 0, union, interfaces.Length, mixinInterfaces.Length);
151 return union;
154 protected override void CustomizeGetObjectData(AbstractCodeBuilder codebuilder, ArgumentReference arg1,
155 ArgumentReference arg2)
157 Type[] key_and_object = new Type[] {typeof(String), typeof(Object)};
158 MethodInfo addValueMethod = typeof(SerializationInfo).GetMethod("AddValue", key_and_object);
160 codebuilder.AddStatement(new ExpressionStatement(
161 new VirtualMethodInvocationExpression(arg1, addValueMethod,
162 new FixedReference("__target").ToExpression(),
163 _targetField.ToExpression())));
166 protected override Expression GetPseudoInvocationTarget(MethodInfo method)
168 if (Context.HasMixins && _interface2mixinIndex.Contains(method.DeclaringType))
170 return base.GetPseudoInvocationTarget(method);
173 return _targetField.ToExpression();
176 protected override EasyProperty CreateProperty(PropertyInfo property)
178 //The Interceptor Property form the IProxy Interface -> Access the __interceptor Attribute
179 if ("Interceptor".Equals(property.Name) && typeof(IInterceptor).Equals(property.PropertyType))
181 return CreateInterceptorProperty(property);
183 return base.CreateProperty(property);
186 private EasyProperty CreateInterceptorProperty(PropertyInfo propertyInfo)
188 EasyProperty interceptorProperty = MainTypeBuilder.CreateProperty(propertyInfo);
189 EasyMethod getMethod = interceptorProperty.CreateGetMethod();
190 MethodInfo baseMethod = typeof(MulticastDelegate).GetMethod("get_Interceptor");
191 getMethod.CodeBuilder.AddStatement(new ReturnStatement(base.InterceptorField));
192 return interceptorProperty;
195 public virtual Type GenerateCode(Type[] interfaces, Type targetType)
197 if (Context.HasMixins)
199 _mixins = Context.MixinsAsArray();
200 Type[] mixinInterfaces = InspectAndRegisterInterfaces(_mixins);
201 interfaces = Join(interfaces, mixinInterfaces);
204 //interfaces = AddISerializable(interfaces);
205 interfaces = AddInterfaces(new Type[] {typeof(ISerializable), typeof(IProxy)}, interfaces);
207 ReaderWriterLock rwlock = ModuleScope.RWLock;
209 rwlock.AcquireReaderLock(-1);
211 Type cacheType = GetFromCache(targetType, interfaces);
213 if (cacheType != null)
215 rwlock.ReleaseReaderLock();
217 return cacheType;
220 rwlock.UpgradeToWriterLock(-1);
224 cacheType = GetFromCache(targetType, interfaces);
226 if (cacheType != null)
228 return cacheType;
231 _targetType = targetType;
233 CreateTypeBuilder(GenerateTypeName(targetType, interfaces), typeof(Object), interfaces);
234 GenerateFields();
235 ImplementGetObjectData(interfaces);
236 ImplementCacheInvocationCache();
237 GenerateInterfaceImplementation(interfaces);
238 GenerateConstructor();
240 return CreateType();
242 finally
244 rwlock.ReleaseWriterLock();