Fixing 21 PEVerify tests.
[castle.git] / Tools / Castle.DynamicProxy2 / Castle.DynamicProxy / Generators / BaseProxyGenerator.cs
blobb3ee96f11793c19a6a10cf1cb752a051b5eec3a1
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 using System;
16 using System.Collections;
17 using System.Collections.Generic;
18 using System.Diagnostics;
19 using System.Reflection;
20 using System.Reflection.Emit;
21 using System.Runtime.Serialization;
22 using Castle.Core.Interceptor;
23 using Castle.DynamicProxy.Generators.Emitters;
24 using Castle.DynamicProxy.Generators.Emitters.CodeBuilders;
25 using Castle.DynamicProxy.Generators.Emitters.SimpleAST;
26 using Castle.DynamicProxy.Serialization;
28 namespace Castle.DynamicProxy.Generators
30 #if DOTNET2
31 using System.Collections.Generic;
32 #endif
34 public enum ConstructorVersion
36 WithTargetMethod,
37 WithoutTargetMethod
40 /// <summary>
41 /// Base class that exposes the common functionalities
42 /// to proxy generation.
43 /// </summary>
44 /// <remarks>
45 /// TODO:
46 /// - Use the interceptor selector if provided
47 /// - Add tests and fixes for 'leaking this' problem
48 /// - Mixin support
49 /// </remarks>
50 [CLSCompliant(false)]
51 public abstract class BaseProxyGenerator
53 private static MethodInfo invocation_getArgumentsMethod = typeof (AbstractInvocation).GetMethod("get_Arguments");
55 private readonly ModuleScope scope;
56 private int nestedCounter, callbackCounter;
57 private int fieldCount = 1;
58 private FieldReference typeTokenField;
59 private Hashtable method2TokenField = new Hashtable();
60 private IList generateNewSlot = new ArrayList();
61 protected IList methodsToSkip = new ArrayList();
63 protected readonly Type targetType;
64 protected IProxyGenerationHook generationHook;
65 protected ConstructorInfo serializationConstructor;
66 protected Dictionary<Type, int> mixinInterface2MixinIndex = new Dictionary<Type, int>();
67 protected Dictionary<Type, FieldReference> interface2MixinFieldReference = new Dictionary<Type, FieldReference>();
68 protected Dictionary<MethodInfo, Type> method2MixinType = new Dictionary<MethodInfo, Type>();
70 protected BaseProxyGenerator(ModuleScope scope, Type targetType)
72 CheckNotGenericTypeDefinition(targetType, "targetType");
73 this.scope = scope;
74 this.targetType = targetType;
78 protected void CheckNotGenericTypeDefinition(Type type, string argumentName)
80 if (type != null && type.IsGenericTypeDefinition)
82 throw new ArgumentException("Type cannot be a generic type definition. Type: " + type.FullName, argumentName);
86 protected void CheckNotGenericTypeDefinitions(IEnumerable types, string argumentName)
88 if (types != null)
90 foreach (Type t in types)
92 CheckNotGenericTypeDefinition(t, argumentName);
97 protected ModuleScope Scope
99 get { return scope; }
102 protected virtual ClassEmitter BuildClassEmitter(String typeName, Type parentType, IList interfaceList)
104 CheckNotGenericTypeDefinition(parentType, "parentType");
105 CheckNotGenericTypeDefinitions(interfaceList, "interfaceList");
107 Type[] interfaces = new Type[interfaceList.Count];
109 interfaceList.CopyTo(interfaces, 0);
111 return BuildClassEmitter(typeName, parentType, interfaces);
114 protected virtual ClassEmitter BuildClassEmitter(String typeName, Type parentType, Type[] interfaces)
116 CheckNotGenericTypeDefinition(parentType, "parentType");
117 CheckNotGenericTypeDefinitions(interfaces, "interfaceList");
119 if (interfaces == null)
121 interfaces = new Type[0];
124 return new ClassEmitter(Scope, typeName, parentType, interfaces, true);
127 /// <summary>
128 /// Used by dinamically implement <see cref="Core.Interceptor.IProxyTargetAccessor"/>
129 /// </summary>
130 /// <returns></returns>
131 protected abstract Reference GetProxyTargetReference();
133 protected abstract bool CanOnlyProxyVirtual();
135 #region Cache related
137 protected Type GetFromCache(CacheKey key)
139 return scope.GetFromCache(key);
142 protected void AddToCache(CacheKey key, Type type)
144 scope.RegisterInCache(key, type);
147 #endregion
149 protected MethodEmitter CreateProxiedMethod(
150 Type targetType,
151 MethodInfo method,
152 ClassEmitter emitter,
153 NestedClassEmitter invocationImpl,
154 FieldReference interceptorsField,
155 Reference targetRef,
156 ConstructorVersion version,
157 MethodInfo methodOnTarget)
159 CheckNotGenericTypeDefinition(targetType, "targetType");
161 MethodAttributes atts = ObtainMethodAttributes(method);
162 MethodEmitter methodEmitter = emitter.CreateMethod(method.Name, atts);
164 return
165 ImplementProxiedMethod(targetType,
166 methodEmitter,
167 method,
168 emitter,
169 invocationImpl,
170 interceptorsField,
171 targetRef,
172 version,
173 methodOnTarget);
176 protected void ImplementBlankInterface(
177 Type targetType,
178 Type _interface,
179 ClassEmitter emitter,
180 FieldReference interceptorsField,
181 ConstructorEmitter typeInitializerConstructor)
183 CheckNotGenericTypeDefinition(targetType, "targetType");
184 CheckNotGenericTypeDefinition(_interface, "_interface");
186 PropertyToGenerate[] propsToGenerate;
187 EventToGenerate[] eventsToGenerate;
188 MethodInfo[] methods = CollectMethodsAndProperties(emitter, _interface, false, out propsToGenerate, out eventsToGenerate);
190 Dictionary<MethodInfo, NestedClassEmitter> method2Invocation = new Dictionary<MethodInfo, NestedClassEmitter>();
192 foreach (MethodInfo method in methods)
194 AddFieldToCacheMethodTokenAndStatementsToInitialize(method, typeInitializerConstructor, emitter);
196 method2Invocation[method] =
197 BuildInvocationNestedType(emitter,
198 targetType,
199 emitter.TypeBuilder,
200 method,
201 null,
202 ConstructorVersion.WithoutTargetMethod);
205 foreach (MethodInfo method in methods)
207 if (method.IsSpecialName && (method.Name.StartsWith("get_") || method.Name.StartsWith("set_")))
209 continue;
212 NestedClassEmitter nestedClass = method2Invocation[method];
214 MethodEmitter newProxiedMethod =
215 CreateProxiedMethod(targetType,
216 method,
217 emitter,
218 nestedClass,
219 interceptorsField,
220 SelfReference.Self,
221 ConstructorVersion.WithoutTargetMethod,
222 null);
224 ReplicateNonInheritableAttributes(method, newProxiedMethod);
227 foreach (PropertyToGenerate propToGen in propsToGenerate)
229 if (propToGen.CanRead)
231 NestedClassEmitter nestedClass = method2Invocation[propToGen.GetMethod];
233 MethodAttributes atts = ObtainMethodAttributes(propToGen.GetMethod);
235 MethodEmitter getEmitter = propToGen.Emitter.CreateGetMethod(atts);
237 ImplementProxiedMethod(targetType,
238 getEmitter,
239 propToGen.GetMethod,
240 emitter,
241 nestedClass,
242 interceptorsField,
243 SelfReference.Self,
244 ConstructorVersion.WithoutTargetMethod,
245 null);
247 ReplicateNonInheritableAttributes(propToGen.GetMethod, getEmitter);
250 if (propToGen.CanWrite)
252 NestedClassEmitter nestedClass = method2Invocation[propToGen.SetMethod];
254 MethodAttributes atts = ObtainMethodAttributes(propToGen.SetMethod);
256 MethodEmitter setEmitter = propToGen.Emitter.CreateSetMethod(atts);
258 ImplementProxiedMethod(targetType,
259 setEmitter,
260 propToGen.SetMethod,
261 emitter,
262 nestedClass,
263 interceptorsField,
264 SelfReference.Self,
265 ConstructorVersion.WithoutTargetMethod,
266 null);
268 ReplicateNonInheritableAttributes(propToGen.SetMethod, setEmitter);
272 foreach (EventToGenerate eventToGenerate in eventsToGenerate)
274 NestedClassEmitter add_nestedClass = method2Invocation[eventToGenerate.AddMethod];
276 MethodAttributes add_atts = ObtainMethodAttributes(eventToGenerate.AddMethod);
278 MethodEmitter addEmitter = eventToGenerate.Emitter.CreateAddMethod(add_atts);
280 ImplementProxiedMethod(targetType,
281 addEmitter,
282 eventToGenerate.AddMethod,
283 emitter,
284 add_nestedClass,
285 interceptorsField,
286 SelfReference.Self,
287 ConstructorVersion.WithoutTargetMethod,
288 null);
290 ReplicateNonInheritableAttributes(eventToGenerate.AddMethod, addEmitter);
292 NestedClassEmitter remove_nestedClass = method2Invocation[eventToGenerate.RemoveMethod];
294 MethodAttributes remove_atts = ObtainMethodAttributes(eventToGenerate.RemoveMethod);
296 MethodEmitter removeEmitter = eventToGenerate.Emitter.CreateRemoveMethod(remove_atts);
298 ImplementProxiedMethod(targetType,
299 removeEmitter,
300 eventToGenerate.RemoveMethod,
301 emitter,
302 remove_nestedClass,
303 interceptorsField,
304 SelfReference.Self,
305 ConstructorVersion.WithoutTargetMethod,
306 null);
308 ReplicateNonInheritableAttributes(eventToGenerate.RemoveMethod, removeEmitter);
312 protected MethodEmitter ImplementProxiedMethod(
313 Type targetType,
314 MethodEmitter methodEmitter,
315 MethodInfo method,
316 ClassEmitter emitter,
317 NestedClassEmitter invocationImpl,
318 FieldReference interceptorsField,
319 Reference targetRef,
320 ConstructorVersion version,
321 MethodInfo methodOnTarget)
323 CheckNotGenericTypeDefinition(targetType, "targetType");
325 methodEmitter.CopyParametersAndReturnTypeFrom(method, emitter);
327 TypeReference[] dereferencedArguments = IndirectReference.WrapIfByRef(methodEmitter.Arguments);
329 Type iinvocation = invocationImpl.TypeBuilder;
331 Trace.Assert(method.IsGenericMethod == iinvocation.IsGenericTypeDefinition);
332 bool isGenericInvocationClass = false;
333 if (method.IsGenericMethod)
335 // bind generic method arguments to invocation's type arguments
336 Type[] genericMethodArgs = method.GetGenericArguments();
337 iinvocation = iinvocation.MakeGenericType(genericMethodArgs);
338 isGenericInvocationClass = true;
341 LocalReference invocationImplLocal = methodEmitter.CodeBuilder.DeclareLocal(iinvocation);
343 // TODO: Initialize iinvocation instance
344 // with ordinary arguments and in and out arguments
346 Expression interceptors = interceptorsField.ToExpression();
348 Expression typeTokenFieldExp = typeTokenField.ToExpression();
349 Expression methodInfoTokenExp;
351 if (method2TokenField.ContainsKey(method)) // Token is in the cache
353 methodInfoTokenExp = ((FieldReference) method2TokenField[method]).ToExpression();
355 else
357 // Not in the cache: generic method
359 methodInfoTokenExp = new MethodTokenExpression(method);
362 ConstructorInfo constructor = invocationImpl.Constructors[0].Builder;
364 if (isGenericInvocationClass)
366 constructor = TypeBuilder.GetConstructor(iinvocation, invocationImpl.Constructors[0].Builder);
369 NewInstanceExpression newInvocImpl;
371 if (version == ConstructorVersion.WithTargetMethod)
373 Expression methodOnTargetTokenExp;
375 if (method2TokenField.ContainsKey(methodOnTarget)) // Token is in the cache
377 methodOnTargetTokenExp = ((FieldReference) method2TokenField[methodOnTarget]).ToExpression();
379 else
381 // Not in the cache: generic method
383 methodOnTargetTokenExp = new MethodTokenExpression(methodOnTarget);
386 newInvocImpl =
387 new NewInstanceExpression(constructor,
388 targetRef.ToExpression(),
389 interceptors,
390 typeTokenFieldExp,
391 methodOnTargetTokenExp,
392 methodInfoTokenExp,
393 new ReferencesToObjectArrayExpression(dereferencedArguments),
394 SelfReference.Self.ToExpression());
396 else
398 newInvocImpl =
399 new NewInstanceExpression(constructor,
400 targetRef.ToExpression(),
401 interceptors,
402 typeTokenFieldExp,
403 methodInfoTokenExp,
404 new ReferencesToObjectArrayExpression(dereferencedArguments),
405 SelfReference.Self.ToExpression());
408 methodEmitter.CodeBuilder.AddStatement(new AssignStatement(invocationImplLocal, newInvocImpl));
410 if (method.ContainsGenericParameters)
412 EmitLoadGenricMethodArguments(methodEmitter, method, invocationImplLocal);
415 methodEmitter.CodeBuilder.AddStatement(
416 new ExpressionStatement(new MethodInvocationExpression(invocationImplLocal, Constants.AbstractInvocationProceed)));
418 CopyOutAndRefParameters(dereferencedArguments, invocationImplLocal, method, methodEmitter);
420 if (method.ReturnType != typeof (void))
422 // Emit code to return with cast from ReturnValue
423 MethodInvocationExpression getRetVal =
424 new MethodInvocationExpression(invocationImplLocal, typeof (AbstractInvocation).GetMethod("get_ReturnValue"));
426 methodEmitter.CodeBuilder.AddStatement(new ReturnStatement(new ConvertExpression(method.ReturnType, getRetVal)));
428 else
430 methodEmitter.CodeBuilder.AddStatement(new ReturnStatement());
433 return methodEmitter;
436 private void EmitLoadGenricMethodArguments(MethodEmitter methodEmitter, MethodInfo method, LocalReference invocationImplLocal)
438 Type[] genericParameters = Array.FindAll(method.GetGenericArguments(), delegate(Type t)
440 return t.IsGenericParameter;
442 LocalReference genericParamsArrayLocal = methodEmitter.CodeBuilder.DeclareLocal(typeof (Type[]));
443 methodEmitter.CodeBuilder.AddStatement(
444 new AssignStatement(genericParamsArrayLocal, new NewArrayExpression(genericParameters.Length, typeof (Type))));
446 for (int i = 0; i < genericParameters.Length; ++i)
448 methodEmitter.CodeBuilder.AddStatement(
449 new AssignArrayStatement(genericParamsArrayLocal, i, new TypeTokenExpression(genericParameters[i])));
451 MethodInfo setGenericsArgs = typeof (AbstractInvocation).GetMethod("SetGenericMethodArguments", new Type[] {typeof (Type[])});
452 methodEmitter.CodeBuilder.AddStatement(new ExpressionStatement(
453 new MethodInvocationExpression(invocationImplLocal, setGenericsArgs,
454 new ReferenceExpression(genericParamsArrayLocal))));
457 private static void CopyOutAndRefParameters(
458 TypeReference[] dereferencedArguments, LocalReference invocationImplLocal, MethodInfo method, MethodEmitter methodEmitter)
460 ParameterInfo[] parameters = method.GetParameters();
461 bool hasByRefParam = false;
462 for (int i = 0; i < parameters.Length; i++)
464 if (parameters[i].ParameterType.IsByRef)
465 hasByRefParam = true;
467 if (!hasByRefParam)
468 return; //saving the need to create locals if there is no need
469 LocalReference invocationArgs = methodEmitter.CodeBuilder.DeclareLocal(typeof (object[]));
470 methodEmitter.CodeBuilder.AddStatement(
471 new AssignStatement(invocationArgs,
472 new MethodInvocationExpression(invocationImplLocal, invocation_getArgumentsMethod)
475 for (int i = 0; i < parameters.Length; i++)
477 if (parameters[i].ParameterType.IsByRef)
479 methodEmitter.CodeBuilder.AddStatement(
480 new AssignStatement(dereferencedArguments[i],
481 new ConvertExpression(dereferencedArguments[i].Type,
482 new LoadRefArrayElementExpression(i, invocationArgs)
489 protected void GenerateConstructor(ClassEmitter emitter, params FieldReference[] fields)
491 GenerateConstructor(emitter, null, fields);
494 protected void GenerateConstructor(
495 ClassEmitter emitter, ConstructorInfo baseConstructor, params FieldReference[] fields)
497 ArgumentReference[] args;
498 ParameterInfo[] baseConstructorParams = null;
500 if (baseConstructor != null)
502 baseConstructorParams = baseConstructor.GetParameters();
505 if (baseConstructorParams != null && baseConstructorParams.Length != 0)
507 args = new ArgumentReference[fields.Length + baseConstructorParams.Length];
509 int offset = fields.Length;
511 for (int i = offset; i < offset + baseConstructorParams.Length; i++)
513 ParameterInfo paramInfo = baseConstructorParams[i - offset];
514 args[i] = new ArgumentReference(paramInfo.ParameterType);
517 else
519 args = new ArgumentReference[fields.Length];
522 for (int i = 0; i < fields.Length; i++)
524 args[i] = new ArgumentReference(fields[i].Reference.FieldType);
527 ConstructorEmitter constructor = emitter.CreateConstructor(args);
529 for (int i = 0; i < fields.Length; i++)
531 constructor.CodeBuilder.AddStatement(new AssignStatement(fields[i], args[i].ToExpression()));
534 // Invoke base constructor
536 if (baseConstructor != null)
538 ArgumentReference[] slice = new ArgumentReference[baseConstructorParams.Length];
539 Array.Copy(args, fields.Length, slice, 0, baseConstructorParams.Length);
541 constructor.CodeBuilder.InvokeBaseConstructor(baseConstructor, slice);
543 else
545 constructor.CodeBuilder.InvokeBaseConstructor();
548 // Invoke initialize method
550 // constructor.CodeBuilder.AddStatement(
551 // new ExpressionStatement(new MethodInvocationExpression(SelfReference.Self, initCacheMethod)));
553 constructor.CodeBuilder.AddStatement(new ReturnStatement());
556 /// <summary>
557 /// Generates a parameters constructor that initializes the proxy
558 /// state with <see cref="StandardInterceptor"/> just to make it non-null.
559 /// <para>
560 /// This constructor is important to allow proxies to be XML serializable
561 /// </para>
562 /// </summary>
563 protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseClass, FieldReference interceptorField)
565 // Check if the type actually has a default constructor
567 ConstructorInfo defaultConstructor = baseClass.GetConstructor(BindingFlags.Public, null, Type.EmptyTypes, null);
569 if (defaultConstructor == null)
571 defaultConstructor = baseClass.GetConstructor(BindingFlags.NonPublic, null, Type.EmptyTypes, null);
573 if (defaultConstructor == null || defaultConstructor.IsPrivate)
575 return;
579 ConstructorEmitter constructor = emitter.CreateConstructor();
581 // initialize fields with an empty interceptor
583 constructor.CodeBuilder.AddStatement(
584 new AssignStatement(interceptorField, new NewArrayExpression(1, typeof (IInterceptor))));
585 constructor.CodeBuilder.AddStatement(
586 new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof (StandardInterceptor), new Type[0])));
588 // Invoke base constructor
590 constructor.CodeBuilder.InvokeBaseConstructor(defaultConstructor);
592 constructor.CodeBuilder.AddStatement(new ReturnStatement());
595 #region First level attributes
597 protected MethodAttributes ObtainMethodAttributes(MethodInfo method)
599 MethodAttributes atts = MethodAttributes.Virtual;
601 if (ShouldCreateNewSlot(method))
603 atts |= MethodAttributes.NewSlot;
606 if (method.IsPublic)
608 atts |= MethodAttributes.Public;
611 if (method.IsHideBySig)
613 atts |= MethodAttributes.HideBySig;
615 if (InternalsHelper.IsInternal(method) && InternalsHelper.IsInternalToDynamicProxy(method.DeclaringType.Assembly))
617 atts |= MethodAttributes.Assembly;
619 if (method.IsFamilyAndAssembly)
621 atts |= MethodAttributes.FamANDAssem;
623 else if (method.IsFamilyOrAssembly)
625 atts |= MethodAttributes.FamORAssem;
627 else if (method.IsFamily)
629 atts |= MethodAttributes.Family;
632 if (method.Name.StartsWith("set_") || method.Name.StartsWith("get_"))
634 atts |= MethodAttributes.SpecialName;
637 return atts;
640 private PropertyAttributes ObtainPropertyAttributes(PropertyInfo property)
642 PropertyAttributes atts = PropertyAttributes.None;
644 return atts;
647 #endregion
649 protected MethodBuilder CreateCallbackMethod(ClassEmitter emitter, MethodInfo methodInfo, MethodInfo methodOnTarget)
651 MethodInfo targetMethod = methodOnTarget != null ? methodOnTarget : methodInfo;
653 if (targetMethod.IsAbstract)
654 return null;
656 // MethodBuild creation
658 MethodAttributes atts = MethodAttributes.Family;
660 String name = methodInfo.Name + "_callback_" + ++callbackCounter;
662 MethodEmitter callBackMethod = emitter.CreateMethod(name, atts);
664 callBackMethod.CopyParametersAndReturnTypeFrom(targetMethod, emitter);
666 // Generic definition
668 if (targetMethod.IsGenericMethod)
670 targetMethod = targetMethod.MakeGenericMethod(callBackMethod.GenericTypeParams);
673 // Parameters exp
675 Expression[] exps = new Expression[callBackMethod.Arguments.Length];
677 for (int i = 0; i < callBackMethod.Arguments.Length; i++)
679 exps[i] = callBackMethod.Arguments[i].ToExpression();
682 // invocation on base class
684 callBackMethod.CodeBuilder.AddStatement(
685 new ReturnStatement(new MethodInvocationExpression(GetProxyTargetReference(), targetMethod, exps)));
687 return callBackMethod.MethodBuilder;
690 #region IInvocation related
692 /// <summary>
693 /// If callbackMethod is null the InvokeOnTarget implementation
694 /// is just the code to throw an exception
695 /// </summary>
696 /// <param name="emitter"></param>
697 /// <param name="targetType"></param>
698 /// <param name="targetForInvocation"></param>
699 /// <param name="methodInfo"></param>
700 /// <param name="callbackMethod"></param>
701 /// <param name="version"></param>
702 /// <returns></returns>
703 protected NestedClassEmitter BuildInvocationNestedType(
704 ClassEmitter emitter,
705 Type targetType,
706 Type targetForInvocation,
707 MethodInfo methodInfo,
708 MethodInfo callbackMethod,
709 ConstructorVersion version)
711 CheckNotGenericTypeDefinition(targetType, "targetType");
712 CheckNotGenericTypeDefinition(targetForInvocation, "targetForInvocation");
713 return BuildInvocationNestedType(emitter, targetType, targetForInvocation, methodInfo, callbackMethod, version, false);
716 /// <summary>
717 /// If callbackMethod is null the InvokeOnTarget implementation
718 /// is just the code to throw an exception
719 /// </summary>
720 /// <param name="emitter"></param>
721 /// <param name="targetType"></param>
722 /// <param name="targetForInvocation"></param>
723 /// <param name="methodInfo"></param>
724 /// <param name="callbackMethod"></param>
725 /// <param name="version"></param>
726 /// <param name="allowChangeTarget">If true the invocation will implement the IChangeProxyTarget interface</param>
727 /// <returns></returns>
728 protected NestedClassEmitter BuildInvocationNestedType(
729 ClassEmitter emitter,
730 Type targetType,
731 Type targetForInvocation,
732 MethodInfo methodInfo,
733 MethodInfo callbackMethod,
734 ConstructorVersion version,
735 bool allowChangeTarget)
737 CheckNotGenericTypeDefinition(targetType, "targetType");
738 CheckNotGenericTypeDefinition(targetForInvocation, "targetForInvocation");
740 nestedCounter++;
742 Type[] interfaces = new Type[0];
743 if (allowChangeTarget)
745 interfaces = new Type[] {typeof (IChangeProxyTarget)};
748 NestedClassEmitter nested =
749 new NestedClassEmitter(emitter,
750 "Invocation" + methodInfo.Name + "_" + nestedCounter.ToString(),
751 typeof (AbstractInvocation),
752 interfaces);
754 // invocation only needs to mirror the generic parameters of the MethodInfo
755 // targetType cannot be a generic type definition
756 #if DOTNET2
757 nested.CreateGenericParameters(methodInfo.GetGenericArguments ());
758 #endif
759 // Create the invocation fields
761 FieldReference targetRef = nested.CreateField("target", emitter.TypeBuilder);
763 // Create constructor
765 CreateIInvocationConstructor(emitter.TypeBuilder, nested, targetRef, version);
767 if (allowChangeTarget)
769 ArgumentReference argument1 = new ArgumentReference(typeof (object));
770 MethodEmitter methodEmitter =
771 nested.CreateMethod("ChangeInvocationTarget", new ReturnReferenceExpression(typeof (void)), MethodAttributes.Public | MethodAttributes.Virtual, argument1);
772 methodEmitter.CodeBuilder.AddStatement(
773 new AssignStatement(targetRef,
774 new ConvertExpression(targetType, argument1.ToExpression())
777 methodEmitter.CodeBuilder.AddStatement(new ReturnStatement());
780 // InvokeMethodOnTarget implementation
782 if (callbackMethod != null)
784 ParameterInfo[] parameters = methodInfo.GetParameters();
786 CreateIInvocationInvokeOnTarget(emitter, nested, parameters, targetRef, callbackMethod);
788 else if (IsMixinMethod(methodInfo))
790 ParameterInfo[] parameters = methodInfo.GetParameters();
791 CreateIInvocationInvokeOnTarget(emitter, nested, parameters, targetRef, methodInfo);
793 else
795 CreateEmptyIInvocationInvokeOnTarget(nested);
798 nested.DefineCustomAttribute(new SerializableAttribute());
800 return nested;
803 protected bool IsMixinMethod(MethodInfo methodInfo)
805 return method2MixinType.ContainsKey(methodInfo);
809 private Expression[] CreateArgumentsExpressions(Hashtable byRefArguments, MethodEmitter method, NestedClassEmitter nested, ParameterInfo[] parameters)
811 Expression[] args = new Expression[parameters.Length];
813 // Idea: instead of grab parameters one by one
814 // we should grab an array
815 for (int i = 0; i < parameters.Length; i++)
817 ParameterInfo param = parameters[i];
819 Type paramType = param.ParameterType;
821 if (HasGenericParameters(paramType))
823 paramType = paramType.GetGenericTypeDefinition().MakeGenericType(nested.GetGenericArgumentsFor(paramType));
825 else if (paramType.IsGenericParameter)
827 paramType = nested.GetGenericArgument(paramType.Name);
830 if (paramType.IsByRef)
832 LocalReference localReference = method.CodeBuilder.DeclareLocal(paramType.GetElementType());
833 method.CodeBuilder.AddStatement(
834 new AssignStatement(localReference,
835 new ConvertExpression(paramType.GetElementType(),
836 new MethodInvocationExpression(SelfReference.Self,
837 typeof (AbstractInvocation).GetMethod("GetArgumentValue"),
838 new LiteralIntExpression(i)))));
839 ByRefReference byRefReference = new ByRefReference(localReference);
840 args[i] = new ReferenceExpression(byRefReference);
841 byRefArguments[i] = localReference;
843 else
845 args[i] =
846 new ConvertExpression(paramType,
847 new MethodInvocationExpression(SelfReference.Self,
848 typeof (AbstractInvocation).GetMethod("GetArgumentValue"),
849 new LiteralIntExpression(i)));
852 return args;
855 protected void CreateIInvocationInvokeOnTarget(
856 ClassEmitter targetTypeEmitter,
857 NestedClassEmitter nested,
858 ParameterInfo[] parameters,
859 FieldReference targetField,
860 MethodInfo callbackMethod)
862 const MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual;
864 MethodEmitter method =
865 nested.CreateMethod("InvokeMethodOnTarget", new ReturnReferenceExpression(typeof (void)), methodAtts);
867 Hashtable byRefArguments = new Hashtable();
868 Expression[] args = CreateArgumentsExpressions(byRefArguments, method, nested, parameters);
871 MethodInvocationExpression baseMethodInvExp;
873 if (callbackMethod.IsGenericMethod)
875 callbackMethod = callbackMethod.MakeGenericMethod(nested.GetGenericArgumentsFor(callbackMethod));
878 baseMethodInvExp = new MethodInvocationExpression(targetField, callbackMethod, args);
880 LocalReference ret_local = null;
882 if (callbackMethod.ReturnType != typeof (void))
884 if (callbackMethod.ReturnType.IsGenericParameter)
886 ret_local = method.CodeBuilder.DeclareLocal(nested.GetGenericArgument(callbackMethod.ReturnType.Name));
888 else if (HasGenericParameters(callbackMethod.ReturnType))
890 ret_local =
891 method.CodeBuilder.DeclareLocal(
892 callbackMethod.ReturnType.GetGenericTypeDefinition().MakeGenericType(
893 nested.GetGenericArgumentsFor(callbackMethod.ReturnType)));
895 else
897 ret_local = method.CodeBuilder.DeclareLocal(callbackMethod.ReturnType);
900 method.CodeBuilder.AddStatement(new AssignStatement(ret_local, baseMethodInvExp));
902 else
904 method.CodeBuilder.AddStatement(new ExpressionStatement(baseMethodInvExp));
907 foreach (DictionaryEntry byRefArgument in byRefArguments)
909 int index = (int) byRefArgument.Key;
910 LocalReference localReference = (LocalReference) byRefArgument.Value;
911 method.CodeBuilder.AddStatement(
912 new ExpressionStatement(
913 new MethodInvocationExpression(SelfReference.Self,
914 typeof (AbstractInvocation).GetMethod("SetArgumentValue"),
915 new LiteralIntExpression(index),
916 new ConvertExpression(typeof (object), localReference.Type, new ReferenceExpression(localReference)))
920 if (callbackMethod.ReturnType != typeof (void))
922 MethodInvocationExpression setRetVal =
923 new MethodInvocationExpression(SelfReference.Self,
924 typeof (AbstractInvocation).GetMethod("set_ReturnValue"),
925 new ConvertExpression(typeof (object), ret_local.Type, ret_local.ToExpression()));
927 method.CodeBuilder.AddStatement(new ExpressionStatement(setRetVal));
930 method.CodeBuilder.AddStatement(new ReturnStatement());
933 protected void CreateEmptyIInvocationInvokeOnTarget(NestedClassEmitter nested)
935 const MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual;
937 MethodEmitter method =
938 nested.CreateMethod("InvokeMethodOnTarget", new ReturnReferenceExpression(typeof (void)), methodAtts);
940 // TODO: throw exception
942 String message =
943 String.Format("This is a DynamicProxy2 error: the interceptor attempted " +
944 "to 'Proceed' for a method without a target, for example, an interface method or an abstract method");
946 method.CodeBuilder.AddStatement(new ThrowStatement(typeof (NotImplementedException), message));
948 method.CodeBuilder.AddStatement(new ReturnStatement());
951 /// <summary>
952 /// Generates the constructor for the nested class that extends
953 /// <see cref="AbstractInvocation"/>
954 /// </summary>
955 /// <param name="targetFieldType"></param>
956 /// <param name="nested"></param>
957 /// <param name="targetField"></param>
958 /// <param name="version"></param>
959 protected void CreateIInvocationConstructor(
960 Type targetFieldType, NestedClassEmitter nested, FieldReference targetField, ConstructorVersion version)
962 ArgumentReference cArg0 = new ArgumentReference(targetFieldType);
963 ArgumentReference cArg1 = new ArgumentReference(typeof (IInterceptor[]));
964 ArgumentReference cArg2 = new ArgumentReference(typeof (Type));
965 ArgumentReference cArg3 = new ArgumentReference(typeof (MethodInfo));
966 ArgumentReference cArg4 = null;
967 ArgumentReference cArg6 = new ArgumentReference(typeof (object));
969 if (version == ConstructorVersion.WithTargetMethod)
971 cArg4 = new ArgumentReference(typeof (MethodInfo));
974 ArgumentReference cArg5 = new ArgumentReference(typeof (object[]));
977 ConstructorEmitter constructor;
979 if (cArg4 == null)
981 constructor = nested.CreateConstructor(cArg0, cArg1, cArg2, cArg3, cArg5, cArg6);
983 else
985 constructor = nested.CreateConstructor(cArg0, cArg1, cArg2, cArg3, cArg4, cArg5, cArg6);
988 constructor.CodeBuilder.AddStatement(new AssignStatement(targetField, cArg0.ToExpression()));
990 if (cArg4 == null)
992 constructor.CodeBuilder.InvokeBaseConstructor(Constants.AbstractInvocationConstructorWithoutTargetMethod,
993 cArg0,
994 cArg6,
995 cArg1,
996 cArg2,
997 cArg3,
998 cArg5);
1000 else
1002 constructor.CodeBuilder.InvokeBaseConstructor(Constants.AbstractInvocationConstructorWithTargetMethod,
1003 cArg0,
1004 cArg6,
1005 cArg1,
1006 cArg2,
1007 cArg3,
1008 cArg4,
1009 cArg5);
1012 constructor.CodeBuilder.AddStatement(new ReturnStatement());
1015 #endregion
1017 #region Custom Attribute handling
1019 protected void ReplicateNonInheritableAttributes(Type targetType, ClassEmitter emitter)
1021 object[] attrs = targetType.GetCustomAttributes(false);
1023 foreach (Attribute attribute in attrs)
1025 if (IsInheritable(attribute)) continue;
1027 emitter.DefineCustomAttribute(attribute);
1031 protected void ReplicateNonInheritableAttributes(MethodInfo method, MethodEmitter emitter)
1033 object[] attrs = method.GetCustomAttributes(false);
1035 foreach (Attribute attribute in attrs)
1037 if (IsInheritable(attribute)) continue;
1039 emitter.DefineCustomAttribute(attribute);
1043 #endregion
1045 #region Type tokens related operations
1047 protected void GenerateConstructors(ClassEmitter emitter, Type baseType, params FieldReference[] fields)
1049 ConstructorInfo[] constructors =
1050 baseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1052 foreach (ConstructorInfo constructor in constructors)
1054 if (constructor.IsPrivate) continue;
1056 GenerateConstructor(emitter, constructor, fields);
1060 protected ConstructorEmitter GenerateStaticConstructor(ClassEmitter emitter)
1062 return emitter.CreateTypeConstructor();
1065 /// <summary>
1066 /// Improvement: this cache should be static. We should generate a
1067 /// type constructor instead
1068 /// </summary>
1069 protected void CreateInitializeCacheMethodBody(
1070 Type targetType, MethodInfo[] methods, ClassEmitter classEmitter, ConstructorEmitter typeInitializerConstructor)
1072 typeTokenField = classEmitter.CreateStaticField("typeTokenCache", typeof (Type));
1074 typeInitializerConstructor.CodeBuilder.AddStatement(
1075 new AssignStatement(typeTokenField, new TypeTokenExpression(targetType)));
1077 CacheMethodTokens(classEmitter, methods, typeInitializerConstructor);
1080 protected void CacheMethodTokens(
1081 ClassEmitter classEmitter, MethodInfo[] methods, ConstructorEmitter typeInitializerConstructor)
1083 foreach (MethodInfo method in methods)
1085 // Aparently we cannot cache generic methods
1086 if (method.IsGenericMethod) continue;
1088 AddFieldToCacheMethodTokenAndStatementsToInitialize(method, typeInitializerConstructor, classEmitter);
1092 protected void AddFieldToCacheMethodTokenAndStatementsToInitialize(
1093 MethodInfo method, ConstructorEmitter typeInitializerConstructor, ClassEmitter classEmitter)
1095 if (!method2TokenField.ContainsKey(method))
1097 FieldReference fieldCache =
1098 classEmitter.CreateStaticField("tokenCache" + fieldCount++, typeof (MethodInfo));
1100 method2TokenField.Add(method, fieldCache);
1102 typeInitializerConstructor.CodeBuilder.AddStatement(
1103 new AssignStatement(fieldCache, new MethodTokenExpression(method)));
1107 protected void CompleteInitCacheMethod(ConstructorCodeBuilder constCodeBuilder)
1109 constCodeBuilder.AddStatement(new ReturnStatement());
1112 protected void AddDefaultInterfaces(IList interfaceList)
1114 if (!interfaceList.Contains(typeof (IProxyTargetAccessor)))
1116 interfaceList.Add(typeof (IProxyTargetAccessor));
1120 protected void ImplementProxyTargetAccessor(Type targetType, ClassEmitter emitter, FieldReference interceptorsField)
1122 MethodAttributes attributes = MethodAttributes.Virtual | MethodAttributes.Public;
1124 MethodEmitter DynProxyGetTarget =
1125 emitter.CreateMethod("DynProxyGetTarget", attributes, new ReturnReferenceExpression(typeof (object)));
1127 DynProxyGetTarget.CodeBuilder.AddStatement(
1128 new ReturnStatement(new ConvertExpression(typeof (object), targetType, GetProxyTargetReference().ToExpression())));
1130 MethodEmitter GetInterceptors =
1131 emitter.CreateMethod("GetInterceptors", attributes, new ReturnReferenceExpression(typeof (IInterceptor[])));
1133 GetInterceptors.CodeBuilder.AddStatement(
1134 new ReturnStatement(interceptorsField)
1138 #endregion
1140 #region Utility methods
1142 protected void CollectMethodsToProxy(ArrayList methodList, Type type, bool onlyVirtuals)
1144 CollectMethods(methodList, type, onlyVirtuals);
1146 if (type.IsInterface)
1148 Type[] typeChain = type.FindInterfaces(new TypeFilter(NoFilter), null);
1150 foreach (Type interType in typeChain)
1152 CollectMethods(methodList, interType, onlyVirtuals);
1157 protected void CollectPropertyMethodsToProxy(
1158 ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter, out PropertyToGenerate[] propsToGenerate)
1160 if (type.IsInterface)
1162 ArrayList toGenerateList = new ArrayList();
1164 toGenerateList.AddRange(CollectProperties(methodList, type, onlyVirtuals, emitter));
1166 Type[] typeChain = type.FindInterfaces(new TypeFilter(NoFilter), null);
1168 foreach (Type interType in typeChain)
1170 toGenerateList.AddRange(CollectProperties(methodList, interType, onlyVirtuals, emitter));
1173 propsToGenerate = (PropertyToGenerate[]) toGenerateList.ToArray(typeof (PropertyToGenerate));
1175 else
1177 propsToGenerate = CollectProperties(methodList, type, onlyVirtuals, emitter);
1181 /// <summary>
1182 /// Performs some basic screening and invokes the <see cref="IProxyGenerationHook"/>
1183 /// to select methods.
1184 /// </summary>
1185 /// <param name="method"></param>
1186 /// <param name="onlyVirtuals"></param>
1187 /// <returns></returns>
1188 protected bool AcceptMethod(MethodInfo method, bool onlyVirtuals)
1190 // we can never intercept a sealed (final) method
1191 if (method.IsFinal)
1192 return false;
1194 bool isInternalsAndNotVisibleToDynamicProxy = InternalsHelper.IsInternal(method)
1195 && InternalsHelper.IsInternalToDynamicProxy(method.DeclaringType.Assembly) == false;
1196 if (isInternalsAndNotVisibleToDynamicProxy)
1197 return false;
1199 if (onlyVirtuals && !method.IsVirtual)
1201 if (method.DeclaringType != typeof (object) && method.DeclaringType != typeof (MarshalByRefObject))
1203 generationHook.NonVirtualMemberNotification(targetType, method);
1206 return false;
1209 //can only proxy methods that are public or protected (or internals that have already been checked above)
1210 if ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly || method.IsFamilyAndAssembly) == false)
1211 return false;
1213 if (method.DeclaringType == typeof (object))
1215 return false;
1217 if (method.DeclaringType == typeof (MarshalByRefObject))
1219 return false;
1222 return generationHook.ShouldInterceptMethod(targetType, method);
1226 protected MethodInfo[] CollectMethodsAndProperties(
1227 ClassEmitter emitter,
1228 Type targetType,
1229 out PropertyToGenerate[] propsToGenerate,
1230 out EventToGenerate[] eventsToGenerate)
1232 bool onlyVirtuals = CanOnlyProxyVirtual();
1234 return CollectMethodsAndProperties(emitter, targetType, onlyVirtuals, out propsToGenerate, out eventsToGenerate);
1237 protected MethodInfo[] CollectMethodsAndProperties(
1238 ClassEmitter emitter,
1239 Type targetType,
1240 bool onlyVirtuals,
1241 out PropertyToGenerate[] propsToGenerate,
1242 out EventToGenerate[] eventsToGenerate)
1244 ArrayList methodsList = new ArrayList();
1246 CollectMethodsToProxy(methodsList, targetType, onlyVirtuals);
1247 CollectPropertyMethodsToProxy(methodsList, targetType, onlyVirtuals, emitter, out propsToGenerate);
1248 CollectEventMethodsToProxy(methodsList, targetType, onlyVirtuals, emitter, out eventsToGenerate);
1249 return (MethodInfo[]) methodsList.ToArray(typeof (MethodInfo));
1252 private void CollectEventMethodsToProxy(
1253 ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter, out EventToGenerate[] eventsToGenerates)
1255 if (type.IsInterface)
1257 ArrayList toGenerateList = new ArrayList();
1259 toGenerateList.AddRange(CollectEvents(methodList, type, onlyVirtuals, emitter));
1261 Type[] typeChain = type.FindInterfaces(new TypeFilter(NoFilter), null);
1263 foreach (Type interType in typeChain)
1265 toGenerateList.AddRange(CollectEvents(methodList, interType, onlyVirtuals, emitter));
1268 eventsToGenerates = (EventToGenerate[]) toGenerateList.ToArray(typeof (EventToGenerate));
1270 else
1272 eventsToGenerates = CollectEvents(methodList, type, onlyVirtuals, emitter);
1276 /// <summary>
1277 /// Checks if the method is public or protected.
1278 /// </summary>
1279 /// <param name="method"></param>
1280 /// <returns></returns>
1281 private bool IsAccessible(MethodInfo method)
1283 return method.IsPublic || method.IsFamily || method.IsFamilyAndAssembly || method.IsFamilyOrAssembly;
1286 private bool HasGenericParameters(Type type)
1288 if (type.IsGenericType)
1290 Type[] genTypes = type.GetGenericArguments();
1292 foreach (Type genType in genTypes)
1294 if (genType.IsGenericParameter)
1296 return true;
1301 return false;
1304 private bool NoFilter(Type type, object filterCriteria)
1306 return true;
1309 private void CollectMethods(ArrayList methodsList, Type type, bool onlyVirtuals)
1311 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1313 MethodInfo[] methods = type.GetMethods(flags);
1315 foreach (MethodInfo method in methods)
1317 if (method.IsFinal)
1319 AddMethodToGenerateNewSlot(method);
1320 continue;
1323 if (method.IsSpecialName)
1325 continue;
1328 if (AcceptMethod(method, onlyVirtuals))
1330 methodsList.Add(method);
1335 private EventToGenerate[] CollectEvents(ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter)
1337 ArrayList toGenerateList = new ArrayList();
1339 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1341 EventInfo[] events = type.GetEvents(flags);
1343 foreach (EventInfo eventInfo in events)
1345 MethodInfo addMethod = eventInfo.GetAddMethod(true);
1346 MethodInfo removeMethod = eventInfo.GetRemoveMethod(true);
1347 bool shouldGenerate = false;
1349 if (addMethod != null && IsAccessible(addMethod) && AcceptMethod(addMethod, onlyVirtuals))
1351 shouldGenerate = true;
1352 methodList.Add(addMethod);
1355 if (removeMethod != null && IsAccessible(removeMethod) && AcceptMethod(removeMethod, onlyVirtuals))
1357 shouldGenerate = true;
1358 methodList.Add(removeMethod);
1361 if (shouldGenerate == false)
1362 continue;
1364 EventAttributes atts = ObtainEventAttributes(eventInfo);
1366 EventEmitter eventEmitter = emitter.CreateEvent(eventInfo.Name, atts, eventInfo.EventHandlerType);
1368 EventToGenerate eventToGenerate = new EventToGenerate(eventEmitter, addMethod, removeMethod, atts);
1370 toGenerateList.Add(eventToGenerate);
1373 return (EventToGenerate[]) toGenerateList.ToArray(typeof (EventToGenerate));
1376 private EventAttributes ObtainEventAttributes(EventInfo eventInfo)
1378 return EventAttributes.None;
1381 private PropertyToGenerate[] CollectProperties(
1382 ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter)
1384 ArrayList toGenerateList = new ArrayList();
1386 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1388 PropertyInfo[] properties = type.GetProperties(flags);
1390 foreach (PropertyInfo propInfo in properties)
1392 bool generateReadable, generateWritable;
1394 generateWritable = generateReadable = false;
1396 MethodInfo setMethod, getMethod;
1397 setMethod = getMethod = null;
1399 if (propInfo.CanRead)
1401 getMethod = propInfo.GetGetMethod(true);
1403 if (IsAccessible(getMethod) && AcceptMethod(getMethod, onlyVirtuals))
1405 methodList.Add(getMethod);
1406 generateReadable = true;
1410 if (propInfo.CanWrite)
1412 setMethod = propInfo.GetSetMethod(true);
1414 if (IsAccessible(setMethod) && AcceptMethod(setMethod, onlyVirtuals))
1416 methodList.Add(setMethod);
1417 generateWritable = true;
1421 if (!generateWritable && !generateReadable)
1423 continue;
1426 PropertyAttributes atts = ObtainPropertyAttributes(propInfo);
1428 PropertyEmitter propEmitter = emitter.CreateProperty(propInfo.Name, atts, propInfo.PropertyType);
1430 PropertyToGenerate propToGenerate =
1431 new PropertyToGenerate(generateReadable, generateWritable, propEmitter, getMethod, setMethod);
1433 toGenerateList.Add(propToGenerate);
1436 return (PropertyToGenerate[]) toGenerateList.ToArray(typeof (PropertyToGenerate));
1439 private bool IsInheritable(Attribute attribute)
1441 object[] attrs = attribute.GetType().GetCustomAttributes(typeof (AttributeUsageAttribute), true);
1443 if (attrs.Length != 0)
1445 AttributeUsageAttribute usage = (AttributeUsageAttribute) attrs[0];
1447 return usage.Inherited;
1450 return true;
1453 #endregion
1455 protected void AddMethodToGenerateNewSlot(MethodInfo method)
1457 generateNewSlot.Add(method);
1460 /// <summary>
1461 /// Checks if the method has the same signature as a method that was marked as
1462 /// one that should generate a new vtable slot.
1463 /// </summary>
1464 protected bool ShouldCreateNewSlot(MethodInfo method)
1466 string methodStr = method.ToString();
1467 foreach (MethodInfo candidate in generateNewSlot)
1469 if (candidate.ToString() == methodStr)
1470 return true;
1472 return false;
1475 protected virtual void ImplementGetObjectData(ClassEmitter emitter, FieldReference interceptorsField, Type[] interfaces)
1477 /*// To prevent re-implementation of this interface.
1478 _generated.Add(typeof(ISerializable));*/
1480 if (interfaces == null)
1481 interfaces = new Type[0];
1483 ArgumentReference arg1 = new ArgumentReference(typeof (SerializationInfo));
1484 ArgumentReference arg2 = new ArgumentReference(typeof (StreamingContext));
1485 MethodEmitter getObjectData = emitter.CreateMethod("GetObjectData",
1486 new ReturnReferenceExpression(typeof (void)), arg1, arg2);
1488 LocalReference interfacesLocal =
1489 getObjectData.CodeBuilder.DeclareLocal(typeof (String[]));
1491 getObjectData.CodeBuilder.AddStatement(
1492 new AssignStatement(interfacesLocal,
1493 new NewArrayExpression(interfaces.Length, typeof (String))));
1495 for (int i = 0; i < interfaces.Length; i++)
1497 getObjectData.CodeBuilder.AddStatement(new AssignArrayStatement(
1498 interfacesLocal, i,
1499 new ConstReference(interfaces[i].AssemblyQualifiedName).ToExpression()));
1502 getObjectData.CodeBuilder.AddStatement(
1503 new ExpressionStatement(new MethodInvocationExpression(null, typeof (ProxySerializer).GetMethod("SerializeBaseProxyData"),
1504 arg1.ToExpression(), SelfReference.Self.ToExpression(), interceptorsField.ToExpression(),
1505 interfacesLocal.ToExpression(), new TypeTokenExpression(emitter.BaseType))));
1507 CustomizeGetObjectData(getObjectData.CodeBuilder, arg1, arg2);
1509 getObjectData.CodeBuilder.AddStatement(new ReturnStatement());
1512 protected virtual void CustomizeGetObjectData(
1513 AbstractCodeBuilder codebuilder, ArgumentReference arg1,
1514 ArgumentReference arg2)
1519 protected bool VerifyIfBaseImplementsGetObjectData(Type baseType)
1521 // If base type implements ISerializable, we have to make sure
1522 // the GetObjectData is marked as virtual
1524 if (typeof (ISerializable).IsAssignableFrom(baseType))
1526 MethodInfo getObjectDataMethod = baseType.GetMethod("GetObjectData",
1527 new Type[] {typeof (SerializationInfo), typeof (StreamingContext)});
1529 if (getObjectDataMethod == null) //explicit interface implementation
1531 return false;
1534 if (!getObjectDataMethod.IsVirtual || getObjectDataMethod.IsFinal)
1536 String message = String.Format("The type {0} implements ISerializable, but GetObjectData is not marked as virtual",
1537 baseType.FullName);
1538 throw new ArgumentException(message);
1541 methodsToSkip.Add(getObjectDataMethod);
1543 serializationConstructor = baseType.GetConstructor(
1544 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
1545 null,
1546 new Type[] {typeof (SerializationInfo), typeof (StreamingContext)},
1547 null);
1549 if (serializationConstructor == null)
1551 String message = String.Format("The type {0} implements ISerializable, but failed to provide a deserialization constructor", baseType.FullName);
1552 throw new ArgumentException(message);
1555 return true;
1557 return false;
1561 protected MethodInfo[] RegisterMixinMethodsAndProperties(
1562 ClassEmitter emitter, ProxyGenerationOptions options,
1563 MethodInfo[] methods,
1564 ref PropertyToGenerate[] propsToGenerate,
1565 ref EventToGenerate[] eventsToGenerate)
1567 List<MethodInfo> withMixinMethods = null;
1568 List<PropertyToGenerate> withMixinProperties = null;
1569 List<EventToGenerate> withMixinEvents = null;
1571 foreach (Type mixinInterface in mixinInterface2MixinIndex.Keys)
1573 PropertyToGenerate[] mixinPropsToGenerate;
1574 EventToGenerate[] mixinEventsToGenerate;
1575 MethodInfo[] mixinMethods = CollectMethodsAndProperties(emitter, mixinInterface, false,
1576 out mixinPropsToGenerate, out mixinEventsToGenerate);
1577 foreach (MethodInfo mixinMethod in mixinMethods)
1579 method2MixinType[mixinMethod] = mixinInterface;
1582 if (mixinMethods.Length > 0)
1584 if (withMixinMethods == null)
1586 withMixinMethods = new List<MethodInfo>(methods);
1588 withMixinMethods.AddRange(mixinMethods);
1591 if (mixinPropsToGenerate.Length > 0)
1593 if (withMixinProperties == null)
1595 withMixinProperties = new List<PropertyToGenerate>(propsToGenerate);
1597 withMixinProperties.AddRange(mixinPropsToGenerate);
1600 if (mixinEventsToGenerate.Length > 0)
1602 if (withMixinEvents == null)
1604 withMixinEvents = new List<EventToGenerate>(eventsToGenerate);
1606 withMixinEvents.AddRange(mixinEventsToGenerate);
1609 if (withMixinMethods != null)
1611 methods = withMixinMethods.ToArray();
1614 if (withMixinProperties != null)
1616 propsToGenerate = withMixinProperties.ToArray();
1619 if (withMixinEvents != null)
1621 eventsToGenerate = withMixinEvents.ToArray();
1625 return methods;
1628 protected FieldReference[] AddMixinFields(ProxyGenerationOptions options, ClassEmitter emitter)
1630 if (options.HasMixins == false)
1631 return new FieldReference[0];
1632 List<FieldReference> mixins = new List<FieldReference>();
1633 foreach (Type type in mixinInterface2MixinIndex.Keys)
1635 FieldReference fieldReference = emitter.CreateField("__mixin_" + type.FullName.Replace(".", "_"), type);
1636 interface2MixinFieldReference[type] = fieldReference;
1637 mixins.Add(fieldReference);
1639 return mixins.ToArray();
1642 protected void AddMixinInterfaces(ProxyGenerationOptions options, ArrayList interfaceList)
1644 if (options.HasMixins == false)
1645 return;
1646 mixinInterface2MixinIndex = options.GetMixinInterfacesAndPositions();
1647 interfaceList.AddRange(mixinInterface2MixinIndex.Keys);
1650 protected Reference GetTargetRef(MethodInfo method, FieldReference[] mixinFields, Reference targetRef)
1652 if (IsMixinMethod(method))
1654 Type interfaceType = method2MixinType[method];
1655 int mixinIndex = mixinInterface2MixinIndex[interfaceType];
1656 targetRef = mixinFields[mixinIndex];
1658 return targetRef;
1661 protected Type GetMethodTargetType(MethodInfo method)
1663 Type methodTargetType = targetType;
1664 if (IsMixinMethod(method))
1665 methodTargetType = method.DeclaringType;
1666 return methodTargetType;