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