1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.DynamicProxy
.Generators
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
38 /// Base class that exposes the common functionalities
39 /// to proxy generation.
43 /// - Use the interceptor selector if provided
44 /// - Add tests and fixes for 'leaking this' problem
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
)
67 this.targetType
= targetType
;
70 public ProxyGenerationOptions ProxyGenerationOptions
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
)
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
);
146 /// Used by dinamically implement <see cref="Core.Interceptor.IProxyTargetAccessor"/>
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
);
167 protected MethodEmitter
CreateProxiedMethod(
170 ClassEmitter emitter
,
171 NestedClassEmitter invocationImpl
,
172 FieldReference interceptorsField
,
174 ConstructorVersion version
,
175 MethodInfo methodOnTarget
)
177 CheckNotGenericTypeDefinition(targetType
, "targetType");
179 MethodAttributes atts
= ObtainMethodAttributes(method
);
180 MethodEmitter methodEmitter
= emitter
.CreateMethod(method
.Name
, atts
);
183 ImplementProxiedMethod(targetType
,
194 protected void ImplementBlankInterface(
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
,
221 ConstructorVersion
.WithoutTargetMethod
);
224 foreach(MethodInfo method
in methods
)
226 if (method
.IsSpecialName
&& (method
.Name
.StartsWith("get_") || method
.Name
.StartsWith("set_")))
231 NestedClassEmitter nestedClass
= method2Invocation
[method
];
233 MethodEmitter newProxiedMethod
=
234 CreateProxiedMethod(targetType
,
240 ConstructorVersion
.WithoutTargetMethod
,
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
,
263 ConstructorVersion
.WithoutTargetMethod
,
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
,
284 ConstructorVersion
.WithoutTargetMethod
,
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
,
301 eventToGenerate
.AddMethod
,
306 ConstructorVersion
.WithoutTargetMethod
,
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
,
319 eventToGenerate
.RemoveMethod
,
324 ConstructorVersion
.WithoutTargetMethod
,
327 ReplicateNonInheritableAttributes(eventToGenerate
.RemoveMethod
, removeEmitter
);
331 protected MethodEmitter
ImplementProxiedMethod(
333 MethodEmitter methodEmitter
,
335 ClassEmitter emitter
,
336 NestedClassEmitter invocationImpl
,
337 FieldReference interceptorsField
,
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
;
370 // TODO: Generate code that checks the return of selector
371 // if no interceptors is returned, should we invoke the base.Method directly?
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();
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();
411 // Not in the cache: generic method
413 methodOnTargetTokenExp
= new MethodTokenExpression(methodOnTarget
.MakeGenericMethod(genericMethodArgs
));
417 new NewInstanceExpression(constructor
,
418 targetRef
.ToExpression(),
421 methodOnTargetTokenExp
,
423 new ReferencesToObjectArrayExpression(dereferencedArguments
),
424 SelfReference
.Self
.ToExpression());
429 new NewInstanceExpression(constructor
,
430 targetRef
.ToExpression(),
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
)));
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;
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
);
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
);
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());
590 /// Generates a parameters constructor that initializes the proxy
591 /// state with <see cref="StandardInterceptor"/> just to make it non-null.
593 /// This constructor is important to allow proxies to be XML serializable
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
)
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
;
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
;
673 private PropertyAttributes
ObtainPropertyAttributes(PropertyInfo property
)
675 PropertyAttributes atts
= PropertyAttributes
.None
;
682 protected MethodBuilder
CreateCallbackMethod(ClassEmitter emitter
, MethodInfo methodInfo
, MethodInfo methodOnTarget
)
684 MethodInfo targetMethod
= methodOnTarget
!= null ? methodOnTarget
: methodInfo
;
686 if (targetMethod
.IsAbstract
)
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
);
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
726 /// If callbackMethod is null the InvokeOnTarget implementation
727 /// is just the code to throw an exception
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
,
739 Type targetForInvocation
,
740 MethodInfo methodInfo
,
741 MethodInfo callbackMethod
,
742 ConstructorVersion version
)
744 CheckNotGenericTypeDefinition(targetType
, "targetType");
745 CheckNotGenericTypeDefinition(targetForInvocation
, "targetForInvocation");
747 BuildInvocationNestedType(emitter
, targetType
, targetForInvocation
, methodInfo
, callbackMethod
, version
, false);
751 /// If callbackMethod is null the InvokeOnTarget implementation
752 /// is just the code to throw an exception
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
,
765 Type targetForInvocation
,
766 MethodInfo methodInfo
,
767 MethodInfo callbackMethod
,
768 ConstructorVersion version
,
769 bool allowChangeTarget
)
771 CheckNotGenericTypeDefinition(targetType
, "targetType");
772 CheckNotGenericTypeDefinition(targetForInvocation
, "targetForInvocation");
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
),
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
);
825 CreateEmptyIInvocationInvokeOnTarget(nested
);
828 nested
.DefineCustomAttribute(new SerializableAttribute());
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(
875 new LiteralIntExpression(i
)))));
876 ByRefReference byRefReference
= new ByRefReference(localReference
);
877 args
[i
] = new ReferenceExpression(byRefReference
);
878 byRefArguments
[i
] = localReference
;
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
))
911 method
.CodeBuilder
.DeclareLocal(
912 callbackMethod
.ReturnType
.GetGenericTypeDefinition().MakeGenericType(
913 nested
.GetGenericArgumentsFor(callbackMethod
.ReturnType
)));
917 ret_local
= method
.CodeBuilder
.DeclareLocal(callbackMethod
.ReturnType
);
920 method
.CodeBuilder
.AddStatement(new AssignStatement(ret_local
, baseMethodInvExp
));
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
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());
973 /// Generates the constructor for the nested class that extends
974 /// <see cref="AbstractInvocation"/>
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
;
1001 constructor
= nested
.CreateConstructor(cArg0
, cArg1
, cArg2
, cArg3
, cArg5
, cArg6
);
1005 constructor
= nested
.CreateConstructor(cArg0
, cArg1
, cArg2
, cArg3
, cArg4
, cArg5
, cArg6
);
1008 constructor
.CodeBuilder
.AddStatement(new AssignStatement(targetField
, cArg0
.ToExpression()));
1012 constructor
.CodeBuilder
.InvokeBaseConstructor(Constants
.AbstractInvocationConstructorWithoutTargetMethod
,
1022 constructor
.CodeBuilder
.InvokeBaseConstructor(Constants
.AbstractInvocationConstructorWithTargetMethod
,
1032 constructor
.CodeBuilder
.AddStatement(new ReturnStatement());
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
);
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();
1086 /// Improvement: this cache should be static. We should generate a
1087 /// type constructor instead
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
)
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
));
1198 propsToGenerate
= CollectProperties(methodList
, type
, onlyVirtuals
, emitter
);
1203 /// Performs some basic screening and invokes the <see cref="IProxyGenerationHook"/>
1204 /// to select methods.
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
1215 bool isInternalsAndNotVisibleToDynamicProxy
= InternalsHelper
.IsInternal(method
);
1216 if (isInternalsAndNotVisibleToDynamicProxy
)
1218 isInternalsAndNotVisibleToDynamicProxy
= InternalsHelper
.IsInternalToDynamicProxy(method
.DeclaringType
.Assembly
) ==
1222 if (isInternalsAndNotVisibleToDynamicProxy
)
1225 if (onlyVirtuals
&& !method
.IsVirtual
)
1227 if (method
.DeclaringType
!= typeof(object) && method
.DeclaringType
!= typeof(MarshalByRefObject
))
1229 ProxyGenerationOptions
.Hook
.NonVirtualMemberNotification(targetType
, method
);
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)
1239 if (method
.DeclaringType
== typeof(object))
1243 if (method
.DeclaringType
== typeof(MarshalByRefObject
))
1248 return ProxyGenerationOptions
.Hook
.ShouldInterceptMethod(targetType
, method
);
1252 protected MethodInfo
[] CollectMethodsAndProperties(
1253 ClassEmitter emitter
,
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
,
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
));
1298 eventsToGenerates
= CollectEvents(methodList
, type
, onlyVirtuals
, emitter
);
1303 /// Checks if the method is public or protected.
1305 /// <param name="method"></param>
1306 /// <returns></returns>
1307 private bool IsAccessible(MethodInfo method
)
1311 || method
.IsFamilyAndAssembly
1312 || method
.IsFamilyOrAssembly
)
1317 if (InternalsHelper
.IsInternalToDynamicProxy(method
.DeclaringType
.Assembly
)
1318 && method
.IsAssembly
)
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
)
1344 private bool NoFilter(Type type
, object filterCriteria
)
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
)
1359 AddMethodToGenerateNewSlot(method
);
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)
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)
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
)
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
));
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.
1487 private bool ShouldSkipAttributeReplication(Attribute attribute
)
1489 if (SpecialCaseAttributThatShouldNotBeReplicated(attribute
))
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
;
1507 protected void AddMethodToGenerateNewSlot(MethodInfo method
)
1509 generateNewSlot
.Add(method
);
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.
1516 protected bool ShouldCreateNewSlot(MethodInfo method
)
1518 string methodStr
= method
.ToString();
1519 foreach(MethodInfo candidate
in generateNewSlot
)
1521 if (candidate
.ToString() == methodStr
)
1527 protected virtual void ImplementGetObjectData(ClassEmitter emitter
, FieldReference interceptorsField
,
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(
1548 new MethodInvocationExpression(null,
1549 typeof(Type
).GetMethod("GetType",
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").
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(
1579 new ConstReference(interfaces
[i
].AssemblyQualifiedName
).ToExpression()));
1582 getObjectData
.CodeBuilder
.AddStatement(new ExpressionStatement(
1583 new MethodInvocationExpression(arg1
, addValueMethod
,
1584 new ConstReference("__interfaces").
1586 interfacesLocal
.ToExpression())));
1588 getObjectData
.CodeBuilder
.AddStatement(new ExpressionStatement(
1589 new MethodInvocationExpression(arg1
, addValueMethod
,
1590 new ConstReference("__baseType").
1592 new ConstReference (emitter
.BaseType
.AssemblyQualifiedName
).ToExpression())));
1594 getObjectData
.CodeBuilder
.AddStatement(new ExpressionStatement(
1595 new MethodInvocationExpression(arg1
, addValueMethod
,
1596 new ConstReference("__proxyGenerationOptions").
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
1627 if (!getObjectDataMethod
.IsVirtual
|| getObjectDataMethod
.IsFinal
)
1629 String message
= String
.Format("The type {0} implements ISerializable, but GetObjectData is not marked as virtual",
1631 throw new ArgumentException(message
);
1634 methodsToSkip
.Add(getObjectDataMethod
);
1636 serializationConstructor
= baseType
.GetConstructor(
1637 BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
,
1639 new Type
[] {typeof(SerializationInfo), typeof(StreamingContext)}
,
1642 if (serializationConstructor
== null)
1645 String
.Format("The type {0} implements ISerializable, but failed to provide a deserialization constructor",
1647 throw new ArgumentException(message
);
1655 private bool SpecialCaseAttributThatShouldNotBeReplicated(Attribute attribute
)
1657 return attribute
.GetType() == typeof(ComImportAttribute
);