Added container accessor to Castle.Core
[castle.git] / Tools / Castle.DynamicProxy2 / Castle.DynamicProxy / Generators / BaseProxyGenerator.cs
blob6240e74f09881b6f33b16f80e5a8e3d7578eb650
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 namespace Castle.DynamicProxy.Generators
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Diagnostics;
21 using System.Reflection;
22 using System.Reflection.Emit;
23 using System.Runtime.InteropServices;
24 using System.Runtime.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;
29 using Castle.DynamicProxy.Serialization;
31 public enum ConstructorVersion
33 WithTargetMethod,
34 WithoutTargetMethod
37 /// <summary>
38 /// Base class that exposes the common functionalities
39 /// to proxy generation.
40 /// </summary>
41 /// <remarks>
42 /// TODO:
43 /// - Use the interceptor selector if provided
44 /// - Add tests and fixes for 'leaking this' problem
45 /// - Mixin support
46 /// </remarks>
47 public abstract class BaseProxyGenerator
49 private static MethodInfo invocation_getArgumentsMethod = typeof(AbstractInvocation).GetMethod("get_Arguments");
51 private readonly ModuleScope scope;
52 private int nestedCounter, callbackCounter;
53 private int fieldCount = 1;
54 private FieldReference typeTokenField;
55 private Hashtable method2TokenField = new Hashtable();
56 private IList generateNewSlot = new ArrayList();
57 protected IList methodsToSkip = new ArrayList();
58 private ProxyGenerationOptions proxyGenerationOptions;
59 private FieldReference proxyGenerationOptionsField;
61 protected readonly Type targetType;
62 protected ConstructorInfo serializationConstructor;
64 protected BaseProxyGenerator(ModuleScope scope, Type targetType)
66 this.scope = scope;
67 this.targetType = targetType;
70 public ProxyGenerationOptions ProxyGenerationOptions
72 get {
73 if (proxyGenerationOptions == null)
75 throw new InvalidOperationException ("ProxyGenerationOptions must be set before being retrieved.");
77 return proxyGenerationOptions;
81 protected void SetGenerationOptions (ProxyGenerationOptions options, ClassEmitter emitter)
83 if (proxyGenerationOptions != null)
85 throw new InvalidOperationException ("ProxyGenerationOptions can only be set once.");
87 proxyGenerationOptions = options;
88 proxyGenerationOptionsField = emitter.CreateStaticField ("proxyGenerationOptions", typeof (ProxyGenerationOptions));
91 protected void InitializeStaticFields (Type builtType)
93 builtType.GetField (proxyGenerationOptionsField.Reference.Name).SetValue (null, ProxyGenerationOptions);
96 protected void CheckNotGenericTypeDefinition(Type type, string argumentName)
98 if (type != null && type.IsGenericTypeDefinition)
100 throw new ArgumentException("Type cannot be a generic type definition. Type: " + type.FullName, argumentName);
104 protected void CheckNotGenericTypeDefinitions(IEnumerable types, string argumentName)
106 if (types != null)
108 foreach(Type t in types)
110 CheckNotGenericTypeDefinition(t, argumentName);
115 protected ModuleScope Scope
117 get { return scope; }
120 protected virtual ClassEmitter BuildClassEmitter(String typeName, Type parentType, IList interfaceList)
122 CheckNotGenericTypeDefinition(parentType, "parentType");
123 CheckNotGenericTypeDefinitions(interfaceList, "interfaceList");
125 Type[] interfaces = new Type[interfaceList.Count];
127 interfaceList.CopyTo(interfaces, 0);
129 return BuildClassEmitter(typeName, parentType, interfaces);
132 protected virtual ClassEmitter BuildClassEmitter(String typeName, Type parentType, Type[] interfaces)
134 CheckNotGenericTypeDefinition(parentType, "parentType");
135 CheckNotGenericTypeDefinitions(interfaces, "interfaceList");
137 if (interfaces == null)
139 interfaces = new Type[0];
142 return new ClassEmitter(Scope, typeName, parentType, interfaces);
145 /// <summary>
146 /// Used by dinamically implement <see cref="Core.Interceptor.IProxyTargetAccessor"/>
147 /// </summary>
148 /// <returns></returns>
149 protected abstract Reference GetProxyTargetReference();
151 protected abstract bool CanOnlyProxyVirtual();
153 #region Cache related
155 protected Type GetFromCache(CacheKey key)
157 return scope.GetFromCache(key);
160 protected void AddToCache(CacheKey key, Type type)
162 scope.RegisterInCache(key, type);
165 #endregion
167 protected MethodEmitter CreateProxiedMethod(
168 Type targetType,
169 MethodInfo method,
170 ClassEmitter emitter,
171 NestedClassEmitter invocationImpl,
172 FieldReference interceptorsField,
173 Reference targetRef,
174 ConstructorVersion version,
175 MethodInfo methodOnTarget)
177 CheckNotGenericTypeDefinition(targetType, "targetType");
179 MethodAttributes atts = ObtainMethodAttributes(method);
180 MethodEmitter methodEmitter = emitter.CreateMethod(method.Name, atts);
182 return
183 ImplementProxiedMethod(targetType,
184 methodEmitter,
185 method,
186 emitter,
187 invocationImpl,
188 interceptorsField,
189 targetRef,
190 version,
191 methodOnTarget);
194 protected void ImplementBlankInterface(
195 Type targetType,
196 Type _interface,
197 ClassEmitter emitter,
198 FieldReference interceptorsField,
199 ConstructorEmitter typeInitializerConstructor)
201 CheckNotGenericTypeDefinition(targetType, "targetType");
202 CheckNotGenericTypeDefinition(_interface, "_interface");
204 PropertyToGenerate[] propsToGenerate;
205 EventToGenerate[] eventsToGenerate;
206 MethodInfo[] methods =
207 CollectMethodsAndProperties(emitter, _interface, false, out propsToGenerate, out eventsToGenerate);
209 Dictionary<MethodInfo, NestedClassEmitter> method2Invocation = new Dictionary<MethodInfo, NestedClassEmitter>();
211 foreach(MethodInfo method in methods)
213 AddFieldToCacheMethodTokenAndStatementsToInitialize(method, typeInitializerConstructor, emitter);
215 method2Invocation[method] =
216 BuildInvocationNestedType(emitter,
217 targetType,
218 emitter.TypeBuilder,
219 method,
220 null,
221 ConstructorVersion.WithoutTargetMethod);
224 foreach(MethodInfo method in methods)
226 if (method.IsSpecialName && (method.Name.StartsWith("get_") || method.Name.StartsWith("set_")))
228 continue;
231 NestedClassEmitter nestedClass = method2Invocation[method];
233 MethodEmitter newProxiedMethod =
234 CreateProxiedMethod(targetType,
235 method,
236 emitter,
237 nestedClass,
238 interceptorsField,
239 SelfReference.Self,
240 ConstructorVersion.WithoutTargetMethod,
241 null);
243 ReplicateNonInheritableAttributes(method, newProxiedMethod);
246 foreach(PropertyToGenerate propToGen in propsToGenerate)
248 if (propToGen.CanRead)
250 NestedClassEmitter nestedClass = method2Invocation[propToGen.GetMethod];
252 MethodAttributes atts = ObtainMethodAttributes(propToGen.GetMethod);
254 MethodEmitter getEmitter = propToGen.Emitter.CreateGetMethod(atts);
256 ImplementProxiedMethod(targetType,
257 getEmitter,
258 propToGen.GetMethod,
259 emitter,
260 nestedClass,
261 interceptorsField,
262 SelfReference.Self,
263 ConstructorVersion.WithoutTargetMethod,
264 null);
266 ReplicateNonInheritableAttributes(propToGen.GetMethod, getEmitter);
269 if (propToGen.CanWrite)
271 NestedClassEmitter nestedClass = method2Invocation[propToGen.SetMethod];
273 MethodAttributes atts = ObtainMethodAttributes(propToGen.SetMethod);
275 MethodEmitter setEmitter = propToGen.Emitter.CreateSetMethod(atts);
277 ImplementProxiedMethod(targetType,
278 setEmitter,
279 propToGen.SetMethod,
280 emitter,
281 nestedClass,
282 interceptorsField,
283 SelfReference.Self,
284 ConstructorVersion.WithoutTargetMethod,
285 null);
287 ReplicateNonInheritableAttributes(propToGen.SetMethod, setEmitter);
291 foreach(EventToGenerate eventToGenerate in eventsToGenerate)
293 NestedClassEmitter add_nestedClass = method2Invocation[eventToGenerate.AddMethod];
295 MethodAttributes add_atts = ObtainMethodAttributes(eventToGenerate.AddMethod);
297 MethodEmitter addEmitter = eventToGenerate.Emitter.CreateAddMethod(add_atts);
299 ImplementProxiedMethod(targetType,
300 addEmitter,
301 eventToGenerate.AddMethod,
302 emitter,
303 add_nestedClass,
304 interceptorsField,
305 SelfReference.Self,
306 ConstructorVersion.WithoutTargetMethod,
307 null);
309 ReplicateNonInheritableAttributes(eventToGenerate.AddMethod, addEmitter);
311 NestedClassEmitter remove_nestedClass = method2Invocation[eventToGenerate.RemoveMethod];
313 MethodAttributes remove_atts = ObtainMethodAttributes(eventToGenerate.RemoveMethod);
315 MethodEmitter removeEmitter = eventToGenerate.Emitter.CreateRemoveMethod(remove_atts);
317 ImplementProxiedMethod(targetType,
318 removeEmitter,
319 eventToGenerate.RemoveMethod,
320 emitter,
321 remove_nestedClass,
322 interceptorsField,
323 SelfReference.Self,
324 ConstructorVersion.WithoutTargetMethod,
325 null);
327 ReplicateNonInheritableAttributes(eventToGenerate.RemoveMethod, removeEmitter);
331 protected MethodEmitter ImplementProxiedMethod(
332 Type targetType,
333 MethodEmitter methodEmitter,
334 MethodInfo method,
335 ClassEmitter emitter,
336 NestedClassEmitter invocationImpl,
337 FieldReference interceptorsField,
338 Reference targetRef,
339 ConstructorVersion version,
340 MethodInfo methodOnTarget)
342 CheckNotGenericTypeDefinition(targetType, "targetType");
344 methodEmitter.CopyParametersAndReturnTypeFrom(method, emitter);
346 TypeReference[] dereferencedArguments = IndirectReference.WrapIfByRef(methodEmitter.Arguments);
348 Type iinvocation = invocationImpl.TypeBuilder;
350 Trace.Assert(method.IsGenericMethod == iinvocation.IsGenericTypeDefinition);
351 bool isGenericInvocationClass = false;
352 Type[] genericMethodArgs = new Type[0];
353 if (method.IsGenericMethod)
355 // bind generic method arguments to invocation's type arguments
356 genericMethodArgs = methodEmitter.MethodBuilder.GetGenericArguments();
357 iinvocation = iinvocation.MakeGenericType(genericMethodArgs);
358 isGenericInvocationClass = true;
361 LocalReference invocationImplLocal = methodEmitter.CodeBuilder.DeclareLocal(iinvocation);
363 // TODO: Initialize iinvocation instance
364 // with ordinary arguments and in and out arguments
366 Expression interceptors;
368 // if (useSelector)
370 // TODO: Generate code that checks the return of selector
371 // if no interceptors is returned, should we invoke the base.Method directly?
373 // else
375 interceptors = interceptorsField.ToExpression();
378 Expression typeTokenFieldExp = typeTokenField.ToExpression();
379 Expression methodInfoTokenExp;
381 if (method2TokenField.ContainsKey(method)) // Token is in the cache
383 methodInfoTokenExp = ((FieldReference) method2TokenField[method]).ToExpression();
385 else
387 // Not in the cache: generic method
389 methodInfoTokenExp = new MethodTokenExpression(method.MakeGenericMethod(genericMethodArgs));
392 ConstructorInfo constructor = invocationImpl.Constructors[0].ConstructorBuilder;
394 if (isGenericInvocationClass)
396 constructor = TypeBuilder.GetConstructor(iinvocation, invocationImpl.Constructors[0].ConstructorBuilder);
399 NewInstanceExpression newInvocImpl;
401 if (version == ConstructorVersion.WithTargetMethod)
403 Expression methodOnTargetTokenExp;
405 if (method2TokenField.ContainsKey(methodOnTarget)) // Token is in the cache
407 methodOnTargetTokenExp = ((FieldReference) method2TokenField[methodOnTarget]).ToExpression();
409 else
411 // Not in the cache: generic method
413 methodOnTargetTokenExp = new MethodTokenExpression(methodOnTarget.MakeGenericMethod(genericMethodArgs));
416 newInvocImpl =
417 new NewInstanceExpression(constructor,
418 targetRef.ToExpression(),
419 interceptors,
420 typeTokenFieldExp,
421 methodOnTargetTokenExp,
422 methodInfoTokenExp,
423 new ReferencesToObjectArrayExpression(dereferencedArguments),
424 SelfReference.Self.ToExpression());
426 else
428 newInvocImpl =
429 new NewInstanceExpression(constructor,
430 targetRef.ToExpression(),
431 interceptors,
432 typeTokenFieldExp,
433 methodInfoTokenExp,
434 new ReferencesToObjectArrayExpression(dereferencedArguments),
435 SelfReference.Self.ToExpression());
438 methodEmitter.CodeBuilder.AddStatement(new AssignStatement(invocationImplLocal, newInvocImpl));
440 if (method.ContainsGenericParameters)
442 EmitLoadGenricMethodArguments(methodEmitter, method.MakeGenericMethod(genericMethodArgs), invocationImplLocal);
445 methodEmitter.CodeBuilder.AddStatement(
446 new ExpressionStatement(new MethodInvocationExpression(invocationImplLocal, Constants.AbstractInvocationProceed)));
448 CopyOutAndRefParameters(dereferencedArguments, invocationImplLocal, method, methodEmitter);
450 if (method.ReturnType != typeof(void))
452 // Emit code to return with cast from ReturnValue
453 MethodInvocationExpression getRetVal =
454 new MethodInvocationExpression(invocationImplLocal, typeof(AbstractInvocation).GetMethod("get_ReturnValue"));
456 methodEmitter.CodeBuilder.AddStatement(
457 new ReturnStatement(new ConvertExpression(methodEmitter.ReturnType, getRetVal)));
459 else
461 methodEmitter.CodeBuilder.AddStatement(new ReturnStatement());
464 return methodEmitter;
467 private void EmitLoadGenricMethodArguments(MethodEmitter methodEmitter, MethodInfo method,
468 LocalReference invocationImplLocal)
470 Type[] genericParameters =
471 Array.FindAll(method.GetGenericArguments(), delegate(Type t) { return t.IsGenericParameter; });
472 LocalReference genericParamsArrayLocal = methodEmitter.CodeBuilder.DeclareLocal(typeof(Type[]));
473 methodEmitter.CodeBuilder.AddStatement(
474 new AssignStatement(genericParamsArrayLocal, new NewArrayExpression(genericParameters.Length, typeof(Type))));
476 for(int i = 0; i < genericParameters.Length; ++i)
478 methodEmitter.CodeBuilder.AddStatement(
479 new AssignArrayStatement(genericParamsArrayLocal, i, new TypeTokenExpression(genericParameters[i])));
481 MethodInfo setGenericsArgs =
482 typeof(AbstractInvocation).GetMethod("SetGenericMethodArguments", new Type[] {typeof(Type[])});
483 methodEmitter.CodeBuilder.AddStatement(new ExpressionStatement(
484 new MethodInvocationExpression(invocationImplLocal, setGenericsArgs,
485 new ReferenceExpression(
486 genericParamsArrayLocal))));
489 private static void CopyOutAndRefParameters(
490 TypeReference[] dereferencedArguments, LocalReference invocationImplLocal, MethodInfo method,
491 MethodEmitter methodEmitter)
493 ParameterInfo[] parameters = method.GetParameters();
494 bool hasByRefParam = false;
495 for(int i = 0; i < parameters.Length; i++)
497 if (parameters[i].ParameterType.IsByRef)
498 hasByRefParam = true;
500 if (!hasByRefParam)
501 return; //saving the need to create locals if there is no need
502 LocalReference invocationArgs = methodEmitter.CodeBuilder.DeclareLocal(typeof(object[]));
503 methodEmitter.CodeBuilder.AddStatement(
504 new AssignStatement(invocationArgs,
505 new MethodInvocationExpression(invocationImplLocal, invocation_getArgumentsMethod)
508 for(int i = 0; i < parameters.Length; i++)
510 if (parameters[i].ParameterType.IsByRef)
512 methodEmitter.CodeBuilder.AddStatement(
513 new AssignStatement(dereferencedArguments[i],
514 new ConvertExpression(dereferencedArguments[i].Type,
515 new LoadRefArrayElementExpression(i, invocationArgs)
522 protected void GenerateConstructor(ClassEmitter emitter, params FieldReference[] fields)
524 GenerateConstructor(emitter, null, fields);
527 protected void GenerateConstructor(
528 ClassEmitter emitter, ConstructorInfo baseConstructor, params FieldReference[] fields)
530 ArgumentReference[] args;
531 ParameterInfo[] baseConstructorParams = null;
533 if (baseConstructor != null)
535 baseConstructorParams = baseConstructor.GetParameters();
538 if (baseConstructorParams != null && baseConstructorParams.Length != 0)
540 args = new ArgumentReference[fields.Length + baseConstructorParams.Length];
542 int offset = fields.Length;
544 for(int i = offset; i < offset + baseConstructorParams.Length; i++)
546 ParameterInfo paramInfo = baseConstructorParams[i - offset];
547 args[i] = new ArgumentReference(paramInfo.ParameterType);
550 else
552 args = new ArgumentReference[fields.Length];
555 for(int i = 0; i < fields.Length; i++)
557 args[i] = new ArgumentReference(fields[i].Reference.FieldType);
560 ConstructorEmitter constructor = emitter.CreateConstructor(args);
562 for(int i = 0; i < fields.Length; i++)
564 constructor.CodeBuilder.AddStatement(new AssignStatement(fields[i], args[i].ToExpression()));
567 // Invoke base constructor
569 if (baseConstructor != null)
571 ArgumentReference[] slice = new ArgumentReference[baseConstructorParams.Length];
572 Array.Copy(args, fields.Length, slice, 0, baseConstructorParams.Length);
574 constructor.CodeBuilder.InvokeBaseConstructor(baseConstructor, slice);
576 else
578 constructor.CodeBuilder.InvokeBaseConstructor();
581 // Invoke initialize method
583 // constructor.CodeBuilder.AddStatement(
584 // new ExpressionStatement(new MethodInvocationExpression(SelfReference.Self, initCacheMethod)));
586 constructor.CodeBuilder.AddStatement(new ReturnStatement());
589 /// <summary>
590 /// Generates a parameters constructor that initializes the proxy
591 /// state with <see cref="StandardInterceptor"/> just to make it non-null.
592 /// <para>
593 /// This constructor is important to allow proxies to be XML serializable
594 /// </para>
595 /// </summary>
596 protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseClass, FieldReference interceptorField)
598 // Check if the type actually has a default constructor
600 ConstructorInfo defaultConstructor = baseClass.GetConstructor(BindingFlags.Public, null, Type.EmptyTypes, null);
602 if (defaultConstructor == null)
604 defaultConstructor = baseClass.GetConstructor(BindingFlags.NonPublic, null, Type.EmptyTypes, null);
606 if (defaultConstructor == null || defaultConstructor.IsPrivate)
608 return;
612 ConstructorEmitter constructor = emitter.CreateConstructor();
614 // initialize fields with an empty interceptor
616 constructor.CodeBuilder.AddStatement(
617 new AssignStatement(interceptorField, new NewArrayExpression(1, typeof(IInterceptor))));
618 constructor.CodeBuilder.AddStatement(
619 new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof(StandardInterceptor), new Type[0])));
621 // Invoke base constructor
623 constructor.CodeBuilder.InvokeBaseConstructor(defaultConstructor);
625 constructor.CodeBuilder.AddStatement(new ReturnStatement());
628 #region First level attributes
630 protected MethodAttributes ObtainMethodAttributes(MethodInfo method)
632 MethodAttributes atts = MethodAttributes.Virtual;
634 if (ShouldCreateNewSlot(method))
636 atts |= MethodAttributes.NewSlot;
639 if (method.IsPublic)
641 atts |= MethodAttributes.Public;
644 if (method.IsHideBySig)
646 atts |= MethodAttributes.HideBySig;
648 if (InternalsHelper.IsInternal(method) && InternalsHelper.IsInternalToDynamicProxy(method.DeclaringType.Assembly))
650 atts |= MethodAttributes.Assembly;
652 if (method.IsFamilyAndAssembly)
654 atts |= MethodAttributes.FamANDAssem;
656 else if (method.IsFamilyOrAssembly)
658 atts |= MethodAttributes.FamORAssem;
660 else if (method.IsFamily)
662 atts |= MethodAttributes.Family;
665 if (method.Name.StartsWith("set_") || method.Name.StartsWith("get_"))
667 atts |= MethodAttributes.SpecialName;
670 return atts;
673 private PropertyAttributes ObtainPropertyAttributes(PropertyInfo property)
675 PropertyAttributes atts = PropertyAttributes.None;
677 return atts;
680 #endregion
682 protected MethodBuilder CreateCallbackMethod(ClassEmitter emitter, MethodInfo methodInfo, MethodInfo methodOnTarget)
684 MethodInfo targetMethod = methodOnTarget != null ? methodOnTarget : methodInfo;
686 if (targetMethod.IsAbstract)
687 return null;
689 // MethodBuild creation
691 MethodAttributes atts = MethodAttributes.Family;
693 String name = methodInfo.Name + "_callback_" + ++callbackCounter;
695 MethodEmitter callBackMethod = emitter.CreateMethod(name, atts);
697 callBackMethod.CopyParametersAndReturnTypeFrom(targetMethod, emitter);
699 // Generic definition
701 if (targetMethod.IsGenericMethod)
703 targetMethod = targetMethod.MakeGenericMethod(callBackMethod.GenericTypeParams);
706 // Parameters exp
708 Expression[] exps = new Expression[callBackMethod.Arguments.Length];
710 for(int i = 0; i < callBackMethod.Arguments.Length; i++)
712 exps[i] = callBackMethod.Arguments[i].ToExpression();
715 // invocation on base class
717 callBackMethod.CodeBuilder.AddStatement(
718 new ReturnStatement(new MethodInvocationExpression(GetProxyTargetReference(), targetMethod, exps)));
720 return callBackMethod.MethodBuilder;
723 #region IInvocation related
725 /// <summary>
726 /// If callbackMethod is null the InvokeOnTarget implementation
727 /// is just the code to throw an exception
728 /// </summary>
729 /// <param name="emitter"></param>
730 /// <param name="targetType"></param>
731 /// <param name="targetForInvocation"></param>
732 /// <param name="methodInfo"></param>
733 /// <param name="callbackMethod"></param>
734 /// <param name="version"></param>
735 /// <returns></returns>
736 protected NestedClassEmitter BuildInvocationNestedType(
737 ClassEmitter emitter,
738 Type targetType,
739 Type targetForInvocation,
740 MethodInfo methodInfo,
741 MethodInfo callbackMethod,
742 ConstructorVersion version)
744 CheckNotGenericTypeDefinition(targetType, "targetType");
745 CheckNotGenericTypeDefinition(targetForInvocation, "targetForInvocation");
746 return
747 BuildInvocationNestedType(emitter, targetType, targetForInvocation, methodInfo, callbackMethod, version, false);
750 /// <summary>
751 /// If callbackMethod is null the InvokeOnTarget implementation
752 /// is just the code to throw an exception
753 /// </summary>
754 /// <param name="emitter"></param>
755 /// <param name="targetType"></param>
756 /// <param name="targetForInvocation"></param>
757 /// <param name="methodInfo"></param>
758 /// <param name="callbackMethod"></param>
759 /// <param name="version"></param>
760 /// <param name="allowChangeTarget">If true the invocation will implement the IChangeProxyTarget interface</param>
761 /// <returns></returns>
762 protected NestedClassEmitter BuildInvocationNestedType(
763 ClassEmitter emitter,
764 Type targetType,
765 Type targetForInvocation,
766 MethodInfo methodInfo,
767 MethodInfo callbackMethod,
768 ConstructorVersion version,
769 bool allowChangeTarget)
771 CheckNotGenericTypeDefinition(targetType, "targetType");
772 CheckNotGenericTypeDefinition(targetForInvocation, "targetForInvocation");
774 nestedCounter++;
776 Type[] interfaces = new Type[0];
778 if (allowChangeTarget)
780 interfaces = new Type[] {typeof(IChangeProxyTarget)};
783 NestedClassEmitter nested =
784 new NestedClassEmitter(emitter,
785 "Invocation" + methodInfo.Name + "_" + nestedCounter.ToString(),
786 typeof(AbstractInvocation),
787 interfaces);
789 // invocation only needs to mirror the generic parameters of the MethodInfo
790 // targetType cannot be a generic type definition
791 nested.CreateGenericParameters(methodInfo.GetGenericArguments());
793 // Create the invocation fields
795 FieldReference targetRef = nested.CreateField("target", targetForInvocation);
797 // Create constructor
799 CreateIInvocationConstructor(targetForInvocation, nested, targetRef, version);
801 if (allowChangeTarget)
803 ArgumentReference argument1 = new ArgumentReference(typeof(object));
804 MethodEmitter methodEmitter =
805 nested.CreateMethod("ChangeInvocationTarget", MethodAttributes.Public | MethodAttributes.Virtual,
806 typeof(void), argument1);
807 methodEmitter.CodeBuilder.AddStatement(
808 new AssignStatement(targetRef,
809 new ConvertExpression(targetType, argument1.ToExpression())
812 methodEmitter.CodeBuilder.AddStatement(new ReturnStatement());
815 // InvokeMethodOnTarget implementation
817 if (callbackMethod != null)
819 ParameterInfo[] parameters = methodInfo.GetParameters();
821 CreateIInvocationInvokeOnTarget(emitter, nested, parameters, targetRef, callbackMethod);
823 else
825 CreateEmptyIInvocationInvokeOnTarget(nested);
828 nested.DefineCustomAttribute(new SerializableAttribute());
830 return nested;
833 protected void CreateIInvocationInvokeOnTarget(
834 ClassEmitter targetTypeEmitter,
835 NestedClassEmitter nested,
836 ParameterInfo[] parameters,
837 FieldReference targetField,
838 MethodInfo callbackMethod)
840 const MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual;
842 MethodEmitter method =
843 nested.CreateMethod ("InvokeMethodOnTarget", methodAtts, typeof (void));
845 Expression[] args = new Expression[parameters.Length];
847 // Idea: instead of grab parameters one by one
848 // we should grab an array
849 Hashtable byRefArguments = new Hashtable();
851 for(int i = 0; i < parameters.Length; i++)
853 ParameterInfo param = parameters[i];
855 Type paramType = param.ParameterType;
857 if (HasGenericParameters(paramType))
859 paramType = paramType.GetGenericTypeDefinition().MakeGenericType(nested.GetGenericArgumentsFor(paramType));
861 else if (paramType.IsGenericParameter)
863 paramType = nested.GetGenericArgument(paramType.Name);
866 if (paramType.IsByRef)
868 LocalReference localReference = method.CodeBuilder.DeclareLocal(paramType.GetElementType());
869 method.CodeBuilder.AddStatement(
870 new AssignStatement(localReference,
871 new ConvertExpression(paramType.GetElementType(),
872 new MethodInvocationExpression(SelfReference.Self,
873 typeof(AbstractInvocation).GetMethod(
874 "GetArgumentValue"),
875 new LiteralIntExpression(i)))));
876 ByRefReference byRefReference = new ByRefReference(localReference);
877 args[i] = new ReferenceExpression(byRefReference);
878 byRefArguments[i] = localReference;
880 else
882 args[i] =
883 new ConvertExpression(paramType,
884 new MethodInvocationExpression(SelfReference.Self,
885 typeof(AbstractInvocation).GetMethod("GetArgumentValue"),
886 new LiteralIntExpression(i)));
890 MethodInvocationExpression baseMethodInvExp;
892 if (callbackMethod.IsGenericMethod)
894 callbackMethod = callbackMethod.MakeGenericMethod(nested.GetGenericArgumentsFor(callbackMethod));
897 baseMethodInvExp = new MethodInvocationExpression(targetField, callbackMethod, args);
898 baseMethodInvExp.VirtualCall = true;
900 LocalReference ret_local = null;
902 if (callbackMethod.ReturnType != typeof(void))
904 if (callbackMethod.ReturnType.IsGenericParameter)
906 ret_local = method.CodeBuilder.DeclareLocal(nested.GetGenericArgument(callbackMethod.ReturnType.Name));
908 else if (HasGenericParameters(callbackMethod.ReturnType))
910 ret_local =
911 method.CodeBuilder.DeclareLocal(
912 callbackMethod.ReturnType.GetGenericTypeDefinition().MakeGenericType(
913 nested.GetGenericArgumentsFor(callbackMethod.ReturnType)));
915 else
917 ret_local = method.CodeBuilder.DeclareLocal(callbackMethod.ReturnType);
920 method.CodeBuilder.AddStatement(new AssignStatement(ret_local, baseMethodInvExp));
922 else
924 method.CodeBuilder.AddStatement(new ExpressionStatement(baseMethodInvExp));
927 foreach(DictionaryEntry byRefArgument in byRefArguments)
929 int index = (int) byRefArgument.Key;
930 LocalReference localReference = (LocalReference) byRefArgument.Value;
931 method.CodeBuilder.AddStatement(
932 new ExpressionStatement(
933 new MethodInvocationExpression(SelfReference.Self,
934 typeof(AbstractInvocation).GetMethod("SetArgumentValue"),
935 new LiteralIntExpression(index),
936 new ConvertExpression(typeof(object), localReference.Type,
937 new ReferenceExpression(localReference)))
941 if (callbackMethod.ReturnType != typeof(void))
943 MethodInvocationExpression setRetVal =
944 new MethodInvocationExpression(SelfReference.Self,
945 typeof(AbstractInvocation).GetMethod("set_ReturnValue"),
946 new ConvertExpression(typeof(object), ret_local.Type, ret_local.ToExpression()));
948 method.CodeBuilder.AddStatement(new ExpressionStatement(setRetVal));
951 method.CodeBuilder.AddStatement(new ReturnStatement());
954 protected void CreateEmptyIInvocationInvokeOnTarget(NestedClassEmitter nested)
956 const MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual;
958 MethodEmitter method =
959 nested.CreateMethod("InvokeMethodOnTarget", methodAtts, typeof(void));
961 // TODO: throw exception
963 String message =
964 String.Format("This is a DynamicProxy2 error: the interceptor attempted " +
965 "to 'Proceed' for a method without a target, for example, an interface method or an abstract method");
967 method.CodeBuilder.AddStatement(new ThrowStatement(typeof(NotImplementedException), message));
969 method.CodeBuilder.AddStatement(new ReturnStatement());
972 /// <summary>
973 /// Generates the constructor for the nested class that extends
974 /// <see cref="AbstractInvocation"/>
975 /// </summary>
976 /// <param name="targetFieldType"></param>
977 /// <param name="nested"></param>
978 /// <param name="targetField"></param>
979 /// <param name="version"></param>
980 protected void CreateIInvocationConstructor(
981 Type targetFieldType, NestedClassEmitter nested, FieldReference targetField, ConstructorVersion version)
983 ArgumentReference cArg0 = new ArgumentReference(targetFieldType);
984 ArgumentReference cArg1 = new ArgumentReference(typeof(IInterceptor[]));
985 ArgumentReference cArg2 = new ArgumentReference(typeof(Type));
986 ArgumentReference cArg3 = new ArgumentReference(typeof(MethodInfo));
987 ArgumentReference cArg4 = null;
988 ArgumentReference cArg6 = new ArgumentReference(typeof(object));
990 if (version == ConstructorVersion.WithTargetMethod)
992 cArg4 = new ArgumentReference(typeof(MethodInfo));
995 ArgumentReference cArg5 = new ArgumentReference(typeof(object[]));
997 ConstructorEmitter constructor;
999 if (cArg4 == null)
1001 constructor = nested.CreateConstructor(cArg0, cArg1, cArg2, cArg3, cArg5, cArg6);
1003 else
1005 constructor = nested.CreateConstructor(cArg0, cArg1, cArg2, cArg3, cArg4, cArg5, cArg6);
1008 constructor.CodeBuilder.AddStatement(new AssignStatement(targetField, cArg0.ToExpression()));
1010 if (cArg4 == null)
1012 constructor.CodeBuilder.InvokeBaseConstructor(Constants.AbstractInvocationConstructorWithoutTargetMethod,
1013 cArg0,
1014 cArg6,
1015 cArg1,
1016 cArg2,
1017 cArg3,
1018 cArg5);
1020 else
1022 constructor.CodeBuilder.InvokeBaseConstructor(Constants.AbstractInvocationConstructorWithTargetMethod,
1023 cArg0,
1024 cArg6,
1025 cArg1,
1026 cArg2,
1027 cArg3,
1028 cArg4,
1029 cArg5);
1032 constructor.CodeBuilder.AddStatement(new ReturnStatement());
1035 #endregion
1037 #region Custom Attribute handling
1039 protected void ReplicateNonInheritableAttributes(Type targetType, ClassEmitter emitter)
1041 object[] attrs = targetType.GetCustomAttributes(false);
1043 foreach(Attribute attribute in attrs)
1045 if (ShouldSkipAttributeReplication(attribute)) continue;
1047 emitter.DefineCustomAttribute(attribute);
1051 protected void ReplicateNonInheritableAttributes(MethodInfo method, MethodEmitter emitter)
1053 object[] attrs = method.GetCustomAttributes(false);
1055 foreach(Attribute attribute in attrs)
1057 if (ShouldSkipAttributeReplication(attribute)) continue;
1059 emitter.DefineCustomAttribute(attribute);
1063 #endregion
1065 #region Type tokens related operations
1067 protected void GenerateConstructors(ClassEmitter emitter, Type baseType, params FieldReference[] fields)
1069 ConstructorInfo[] constructors =
1070 baseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1072 foreach(ConstructorInfo constructor in constructors)
1074 if (constructor.IsPublic || constructor.IsFamily
1075 || (constructor.IsAssembly && InternalsHelper.IsInternalToDynamicProxy(constructor.DeclaringType.Assembly)))
1076 GenerateConstructor(emitter, constructor, fields);
1080 protected ConstructorEmitter GenerateStaticConstructor(ClassEmitter emitter)
1082 return emitter.CreateTypeConstructor();
1085 /// <summary>
1086 /// Improvement: this cache should be static. We should generate a
1087 /// type constructor instead
1088 /// </summary>
1089 protected void CreateInitializeCacheMethodBody(
1090 Type targetType, MethodInfo[] methods, ClassEmitter classEmitter, ConstructorEmitter typeInitializerConstructor)
1092 typeTokenField = classEmitter.CreateStaticField("typeTokenCache", typeof(Type));
1094 typeInitializerConstructor.CodeBuilder.AddStatement(
1095 new AssignStatement(typeTokenField, new TypeTokenExpression(targetType)));
1097 CacheMethodTokens(classEmitter, methods, typeInitializerConstructor);
1100 protected void CacheMethodTokens(
1101 ClassEmitter classEmitter, MethodInfo[] methods, ConstructorEmitter typeInitializerConstructor)
1103 foreach(MethodInfo method in methods)
1105 // Aparently we cannot cache generic methods
1106 if (method.IsGenericMethod) continue;
1108 AddFieldToCacheMethodTokenAndStatementsToInitialize(method, typeInitializerConstructor, classEmitter);
1112 protected void AddFieldToCacheMethodTokenAndStatementsToInitialize(
1113 MethodInfo method, ConstructorEmitter typeInitializerConstructor, ClassEmitter classEmitter)
1115 if (!method2TokenField.ContainsKey(method))
1117 FieldReference fieldCache =
1118 classEmitter.CreateStaticField("tokenCache" + fieldCount++, typeof(MethodInfo));
1120 method2TokenField.Add(method, fieldCache);
1122 typeInitializerConstructor.CodeBuilder.AddStatement(
1123 new AssignStatement(fieldCache, new MethodTokenExpression(method)));
1127 protected void CompleteInitCacheMethod(ConstructorCodeBuilder constCodeBuilder)
1129 constCodeBuilder.AddStatement(new ReturnStatement());
1132 protected void AddDefaultInterfaces(IList interfaceList)
1134 if (!interfaceList.Contains(typeof(IProxyTargetAccessor)))
1136 interfaceList.Add(typeof(IProxyTargetAccessor));
1140 protected void ImplementProxyTargetAccessor(Type targetType, ClassEmitter emitter, FieldReference interceptorsField)
1142 MethodAttributes attributes = MethodAttributes.Virtual | MethodAttributes.Public;
1144 MethodEmitter DynProxyGetTarget =
1145 emitter.CreateMethod("DynProxyGetTarget", attributes, typeof (object));
1147 DynProxyGetTarget.CodeBuilder.AddStatement(
1148 new ReturnStatement(new ConvertExpression(typeof (object), targetType, GetProxyTargetReference().ToExpression())));
1150 MethodEmitter GetInterceptors =
1151 emitter.CreateMethod("GetInterceptors", attributes, typeof (IInterceptor[]));
1153 GetInterceptors.CodeBuilder.AddStatement(
1154 new ReturnStatement(interceptorsField)
1159 #endregion
1161 #region Utility methods
1163 protected void CollectMethodsToProxy(ArrayList methodList, Type type, bool onlyVirtuals)
1165 CollectMethods(methodList, type, onlyVirtuals);
1167 if (type.IsInterface)
1169 Type[] typeChain = type.FindInterfaces(new TypeFilter(NoFilter), null);
1171 foreach(Type interType in typeChain)
1173 CollectMethods(methodList, interType, onlyVirtuals);
1178 protected void CollectPropertyMethodsToProxy(
1179 ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter, out PropertyToGenerate[] propsToGenerate)
1181 if (type.IsInterface)
1183 ArrayList toGenerateList = new ArrayList();
1185 toGenerateList.AddRange(CollectProperties(methodList, type, onlyVirtuals, emitter));
1187 Type[] typeChain = type.FindInterfaces(new TypeFilter(NoFilter), null);
1189 foreach(Type interType in typeChain)
1191 toGenerateList.AddRange(CollectProperties(methodList, interType, onlyVirtuals, emitter));
1194 propsToGenerate = (PropertyToGenerate[]) toGenerateList.ToArray(typeof(PropertyToGenerate));
1196 else
1198 propsToGenerate = CollectProperties(methodList, type, onlyVirtuals, emitter);
1202 /// <summary>
1203 /// Performs some basic screening and invokes the <see cref="IProxyGenerationHook"/>
1204 /// to select methods.
1205 /// </summary>
1206 /// <param name="method"></param>
1207 /// <param name="onlyVirtuals"></param>
1208 /// <returns></returns>
1209 protected bool AcceptMethod(MethodInfo method, bool onlyVirtuals)
1211 // we can never intercept a sealed (final) method
1212 if (method.IsFinal)
1213 return false;
1215 bool isInternalsAndNotVisibleToDynamicProxy = InternalsHelper.IsInternal(method);
1216 if (isInternalsAndNotVisibleToDynamicProxy)
1218 isInternalsAndNotVisibleToDynamicProxy = InternalsHelper.IsInternalToDynamicProxy(method.DeclaringType.Assembly) ==
1219 false;
1222 if (isInternalsAndNotVisibleToDynamicProxy)
1223 return false;
1225 if (onlyVirtuals && !method.IsVirtual)
1227 if (method.DeclaringType != typeof(object) && method.DeclaringType != typeof(MarshalByRefObject))
1229 ProxyGenerationOptions.Hook.NonVirtualMemberNotification(targetType, method);
1232 return false;
1235 //can only proxy methods that are public or protected (or internals that have already been checked above)
1236 if ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly) == false)
1237 return false;
1239 if (method.DeclaringType == typeof(object))
1241 return false;
1243 if (method.DeclaringType == typeof(MarshalByRefObject))
1245 return false;
1248 return ProxyGenerationOptions.Hook.ShouldInterceptMethod(targetType, method);
1252 protected MethodInfo[] CollectMethodsAndProperties(
1253 ClassEmitter emitter,
1254 Type targetType,
1255 out PropertyToGenerate[] propsToGenerate,
1256 out EventToGenerate[] eventsToGenerate)
1258 bool onlyVirtuals = CanOnlyProxyVirtual();
1260 return CollectMethodsAndProperties(emitter, targetType, onlyVirtuals, out propsToGenerate, out eventsToGenerate);
1263 protected MethodInfo[] CollectMethodsAndProperties(
1264 ClassEmitter emitter,
1265 Type targetType,
1266 bool onlyVirtuals,
1267 out PropertyToGenerate[] propsToGenerate,
1268 out EventToGenerate[] eventsToGenerate)
1270 ArrayList methodsList = new ArrayList();
1272 CollectMethodsToProxy(methodsList, targetType, onlyVirtuals);
1273 CollectPropertyMethodsToProxy(methodsList, targetType, onlyVirtuals, emitter, out propsToGenerate);
1274 CollectEventMethodsToProxy(methodsList, targetType, onlyVirtuals, emitter, out eventsToGenerate);
1275 return (MethodInfo[]) methodsList.ToArray(typeof(MethodInfo));
1278 private void CollectEventMethodsToProxy(
1279 ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter, out EventToGenerate[] eventsToGenerates)
1281 if (type.IsInterface)
1283 ArrayList toGenerateList = new ArrayList();
1285 toGenerateList.AddRange(CollectEvents(methodList, type, onlyVirtuals, emitter));
1287 Type[] typeChain = type.FindInterfaces(new TypeFilter(NoFilter), null);
1289 foreach(Type interType in typeChain)
1291 toGenerateList.AddRange(CollectEvents(methodList, interType, onlyVirtuals, emitter));
1294 eventsToGenerates = (EventToGenerate[]) toGenerateList.ToArray(typeof(EventToGenerate));
1296 else
1298 eventsToGenerates = CollectEvents(methodList, type, onlyVirtuals, emitter);
1302 /// <summary>
1303 /// Checks if the method is public or protected.
1304 /// </summary>
1305 /// <param name="method"></param>
1306 /// <returns></returns>
1307 private bool IsAccessible(MethodInfo method)
1309 if (method.IsPublic
1310 || method.IsFamily
1311 || method.IsFamilyAndAssembly
1312 || method.IsFamilyOrAssembly)
1314 return true;
1317 if (InternalsHelper.IsInternalToDynamicProxy(method.DeclaringType.Assembly)
1318 && method.IsAssembly)
1320 return true;
1323 return false;
1326 private bool HasGenericParameters(Type type)
1328 if (type.IsGenericType)
1330 Type[] genTypes = type.GetGenericArguments();
1332 foreach(Type genType in genTypes)
1334 if (genType.IsGenericParameter)
1336 return true;
1341 return false;
1344 private bool NoFilter(Type type, object filterCriteria)
1346 return true;
1349 private void CollectMethods(ArrayList methodsList, Type type, bool onlyVirtuals)
1351 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1353 MethodInfo[] methods = MethodFinder.GetAllInstanceMethods(type, flags);
1355 foreach(MethodInfo method in methods)
1357 if (method.IsFinal)
1359 AddMethodToGenerateNewSlot(method);
1360 continue;
1363 if (method.IsSpecialName
1364 // This is here so we can proxy COM Types built in VB6, where properties
1365 // are let_Foo and set_Foo.
1366 && method.Name.StartsWith("let_") == false)
1368 continue;
1371 if (AcceptMethod(method, onlyVirtuals))
1373 methodsList.Add(method);
1378 private EventToGenerate[] CollectEvents(ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter)
1380 ArrayList toGenerateList = new ArrayList();
1382 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1384 EventInfo[] events = type.GetEvents(flags);
1386 foreach(EventInfo eventInfo in events)
1388 MethodInfo addMethod = eventInfo.GetAddMethod(true);
1389 MethodInfo removeMethod = eventInfo.GetRemoveMethod(true);
1390 bool shouldGenerate = false;
1392 if (addMethod != null && IsAccessible(addMethod) && AcceptMethod(addMethod, onlyVirtuals))
1394 shouldGenerate = true;
1395 methodList.Add(addMethod);
1398 if (removeMethod != null && IsAccessible(removeMethod) && AcceptMethod(removeMethod, onlyVirtuals))
1400 shouldGenerate = true;
1401 methodList.Add(removeMethod);
1404 if (shouldGenerate == false)
1405 continue;
1407 EventAttributes atts = ObtainEventAttributes(eventInfo);
1409 EventEmitter eventEmitter = emitter.CreateEvent(eventInfo.Name, atts, eventInfo.EventHandlerType);
1411 EventToGenerate eventToGenerate = new EventToGenerate(eventEmitter, addMethod, removeMethod, atts);
1413 toGenerateList.Add(eventToGenerate);
1416 return (EventToGenerate[]) toGenerateList.ToArray(typeof(EventToGenerate));
1419 private EventAttributes ObtainEventAttributes(EventInfo eventInfo)
1421 return EventAttributes.None;
1424 private PropertyToGenerate[] CollectProperties(
1425 ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter)
1427 ArrayList toGenerateList = new ArrayList();
1429 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1431 PropertyInfo[] properties = type.GetProperties(flags);
1433 foreach(PropertyInfo propInfo in properties)
1435 bool generateReadable, generateWritable;
1437 generateWritable = generateReadable = false;
1439 MethodInfo setMethod, getMethod;
1440 setMethod = getMethod = null;
1442 if (propInfo.CanRead)
1444 getMethod = propInfo.GetGetMethod(true);
1446 if (IsAccessible(getMethod) && AcceptMethod(getMethod, onlyVirtuals))
1448 methodList.Add(getMethod);
1449 generateReadable = true;
1453 if (propInfo.CanWrite)
1455 setMethod = propInfo.GetSetMethod(true);
1457 if (IsAccessible(setMethod) && AcceptMethod(setMethod, onlyVirtuals))
1459 methodList.Add(setMethod);
1460 generateWritable = true;
1464 if (!generateWritable && !generateReadable)
1466 continue;
1469 PropertyAttributes atts = ObtainPropertyAttributes(propInfo);
1471 PropertyEmitter propEmitter = emitter.CreateProperty(propInfo.Name, atts, propInfo.PropertyType);
1473 PropertyToGenerate propToGenerate =
1474 new PropertyToGenerate(generateReadable, generateWritable, propEmitter, getMethod, setMethod);
1476 toGenerateList.Add(propToGenerate);
1479 return (PropertyToGenerate[]) toGenerateList.ToArray(typeof(PropertyToGenerate));
1482 /// <summary>
1483 /// Attributes should be replicated if they are non-inheritable,
1484 /// but there are some special cases where the attributes means
1485 /// something to the CLR, where they should be skipped.
1486 /// </summary>
1487 private bool ShouldSkipAttributeReplication(Attribute attribute)
1489 if (SpecialCaseAttributThatShouldNotBeReplicated(attribute))
1490 return true;
1492 object[] attrs = attribute.GetType()
1493 .GetCustomAttributes(typeof(AttributeUsageAttribute), true);
1495 if (attrs.Length != 0)
1497 AttributeUsageAttribute usage = (AttributeUsageAttribute) attrs[0];
1499 return usage.Inherited;
1502 return true;
1505 #endregion
1507 protected void AddMethodToGenerateNewSlot(MethodInfo method)
1509 generateNewSlot.Add(method);
1512 /// <summary>
1513 /// Checks if the method has the same signature as a method that was marked as
1514 /// one that should generate a new vtable slot.
1515 /// </summary>
1516 protected bool ShouldCreateNewSlot(MethodInfo method)
1518 string methodStr = method.ToString();
1519 foreach(MethodInfo candidate in generateNewSlot)
1521 if (candidate.ToString() == methodStr)
1522 return true;
1524 return false;
1527 protected virtual void ImplementGetObjectData(ClassEmitter emitter, FieldReference interceptorsField,
1528 Type[] interfaces)
1530 if (interfaces == null)
1532 interfaces = new Type[0];
1535 Type[] get_type_args = new Type[] {typeof(String), typeof(bool), typeof(bool)};
1536 Type[] key_and_object = new Type[] {typeof(String), typeof(Object)};
1537 MethodInfo addValueMethod = typeof(SerializationInfo).GetMethod("AddValue", key_and_object);
1539 ArgumentReference arg1 = new ArgumentReference(typeof(SerializationInfo));
1540 ArgumentReference arg2 = new ArgumentReference(typeof(StreamingContext));
1541 MethodEmitter getObjectData = emitter.CreateMethod("GetObjectData",
1542 typeof(void), arg1, arg2);
1544 LocalReference typeLocal = getObjectData.CodeBuilder.DeclareLocal(typeof(Type));
1546 getObjectData.CodeBuilder.AddStatement(new AssignStatement(
1547 typeLocal,
1548 new MethodInvocationExpression(null,
1549 typeof(Type).GetMethod("GetType",
1550 get_type_args),
1551 new ConstReference(
1552 typeof(ProxyObjectReference).
1553 AssemblyQualifiedName).ToExpression(),
1554 new ConstReference(1).ToExpression(),
1555 new ConstReference(0).ToExpression())));
1557 getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
1558 new MethodInvocationExpression(
1559 arg1, typeof(SerializationInfo).GetMethod("SetType"),
1560 typeLocal.ToExpression())));
1562 getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
1563 new MethodInvocationExpression(arg1, addValueMethod,
1564 new ConstReference("__interceptors").
1565 ToExpression(),
1566 interceptorsField.ToExpression())));
1568 LocalReference interfacesLocal =
1569 getObjectData.CodeBuilder.DeclareLocal(typeof(String[]));
1571 getObjectData.CodeBuilder.AddStatement(
1572 new AssignStatement(interfacesLocal,
1573 new NewArrayExpression(interfaces.Length, typeof(String))));
1575 for(int i = 0; i < interfaces.Length; i++)
1577 getObjectData.CodeBuilder.AddStatement(new AssignArrayStatement(
1578 interfacesLocal, i,
1579 new ConstReference(interfaces[i].AssemblyQualifiedName).ToExpression()));
1582 getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
1583 new MethodInvocationExpression(arg1, addValueMethod,
1584 new ConstReference("__interfaces").
1585 ToExpression(),
1586 interfacesLocal.ToExpression())));
1588 getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
1589 new MethodInvocationExpression(arg1, addValueMethod,
1590 new ConstReference("__baseType").
1591 ToExpression(),
1592 new ConstReference (emitter.BaseType.AssemblyQualifiedName).ToExpression())));
1594 getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
1595 new MethodInvocationExpression(arg1, addValueMethod,
1596 new ConstReference("__proxyGenerationOptions").
1597 ToExpression(),
1598 proxyGenerationOptionsField.ToExpression())));
1600 CustomizeGetObjectData(getObjectData.CodeBuilder, arg1, arg2);
1602 getObjectData.CodeBuilder.AddStatement(new ReturnStatement());
1605 protected virtual void CustomizeGetObjectData(
1606 AbstractCodeBuilder codebuilder, ArgumentReference arg1,
1607 ArgumentReference arg2)
1612 protected bool VerifyIfBaseImplementsGetObjectData(Type baseType)
1614 // If base type implements ISerializable, we have to make sure
1615 // the GetObjectData is marked as virtual
1617 if (typeof(ISerializable).IsAssignableFrom(baseType))
1619 MethodInfo getObjectDataMethod = baseType.GetMethod("GetObjectData",
1620 new Type[] {typeof(SerializationInfo), typeof(StreamingContext)});
1622 if (getObjectDataMethod == null) //explicit interface implementation
1624 return false;
1627 if (!getObjectDataMethod.IsVirtual || getObjectDataMethod.IsFinal)
1629 String message = String.Format("The type {0} implements ISerializable, but GetObjectData is not marked as virtual",
1630 baseType.FullName);
1631 throw new ArgumentException(message);
1634 methodsToSkip.Add(getObjectDataMethod);
1636 serializationConstructor = baseType.GetConstructor(
1637 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
1638 null,
1639 new Type[] {typeof(SerializationInfo), typeof(StreamingContext)},
1640 null);
1642 if (serializationConstructor == null)
1644 String message =
1645 String.Format("The type {0} implements ISerializable, but failed to provide a deserialization constructor",
1646 baseType.FullName);
1647 throw new ArgumentException(message);
1650 return true;
1652 return false;
1655 private bool SpecialCaseAttributThatShouldNotBeReplicated(Attribute attribute)
1657 return attribute.GetType() == typeof(ComImportAttribute);