public Type GenerateCode(Type proxyTargetType, Type[] interfaces, ProxyGenerationOptions options)
		{
			// make sure ProxyGenerationOptions is initialized
			options.Initialize();

			CheckNotGenericTypeDefinition(proxyTargetType, "proxyTargetType");
			CheckNotGenericTypeDefinitions(interfaces, "interfaces");
			Type generatedType;

			ReaderWriterLock rwlock = Scope.RWLock;

			rwlock.AcquireReaderLock(-1);

			CacheKey cacheKey = new CacheKey(proxyTargetType, targetType, interfaces, options);

			Type cacheType = GetFromCache(cacheKey);

			if (cacheType != null)
			{
				rwlock.ReleaseReaderLock();

				return cacheType;
			}

			rwlock.UpgradeToWriterLock(-1);

			try
			{
				cacheType = GetFromCache(cacheKey);

				if (cacheType != null)
				{
					return cacheType;
				}

				SetGenerationOptions (options);

				String newName = targetType.Name + "Proxy" + Guid.NewGuid().ToString("N");

				// Add Interfaces that the proxy implements 

				ArrayList interfaceList = new ArrayList();

				interfaceList.Add(targetType);

				if (interfaces != null)
				{
					interfaceList.AddRange(interfaces);
				}
				if (!interfaceList.Contains(typeof(ISerializable)))
					interfaceList.Add(typeof(ISerializable));

				AddMixinInterfaces(interfaceList);
				AddDefaultInterfaces(interfaceList);

				Type baseType = options.BaseTypeForInterfaceProxy;

				ClassEmitter emitter = BuildClassEmitter(newName, baseType, interfaceList);
				CreateOptionsField (emitter);

				emitter.DefineCustomAttribute(new XmlIncludeAttribute(targetType));
				emitter.DefineCustomAttribute(new SerializableAttribute());

				// Custom attributes
				ReplicateNonInheritableAttributes(targetType, emitter);

				// Fields generations

				FieldReference interceptorsField = emitter.CreateField("__interceptors", typeof(IInterceptor[]));
				targetField = emitter.CreateField("__target", proxyTargetType);

				emitter.DefineCustomAttributeFor(interceptorsField, new XmlIgnoreAttribute());
				emitter.DefineCustomAttributeFor(targetField, new XmlIgnoreAttribute());

				// Implement builtin Interfaces
				ImplementProxyTargetAccessor(targetType, emitter,interceptorsField);
				
				// Collect methods

				PropertyToGenerate[] propsToGenerate;
				EventToGenerate[] eventToGenerates;
				MethodInfo[] methods = CollectMethodsAndProperties(emitter, targetType, out propsToGenerate, out eventToGenerates);

				if (interfaces != null && interfaces.Length != 0)
				{
					ArrayList tmpInterfaces = new ArrayList(interfaces);

					foreach(Type inter in interfaces)
					{
						if (inter.IsAssignableFrom(proxyTargetType))
						{
							PropertyToGenerate[] tempPropsToGenerate;
							EventToGenerate[] tempEventToGenerates;
							MethodInfo[] methodsTemp =
								CollectMethodsAndProperties(emitter, inter, out tempPropsToGenerate, out tempEventToGenerates);

							PropertyToGenerate[] newPropsToGenerate =
								new PropertyToGenerate[tempPropsToGenerate.Length + propsToGenerate.Length];
							MethodInfo[] newMethods = new MethodInfo[methodsTemp.Length + methods.Length];
							EventToGenerate[] newEvents = new EventToGenerate[eventToGenerates.Length + tempEventToGenerates.Length];

							Array.Copy(methods, newMethods, methods.Length);
							Array.Copy(methodsTemp, 0, newMethods, methods.Length, methodsTemp.Length);

							Array.Copy(propsToGenerate, newPropsToGenerate, propsToGenerate.Length);
							Array.Copy(tempPropsToGenerate, 0, newPropsToGenerate, propsToGenerate.Length, tempPropsToGenerate.Length);

							Array.Copy(eventToGenerates, newEvents, eventToGenerates.Length);
							Array.Copy(tempEventToGenerates, 0, newEvents, eventToGenerates.Length, tempEventToGenerates.Length);

							methods = newMethods;
							propsToGenerate = newPropsToGenerate;
							eventToGenerates = newEvents;

							tmpInterfaces.Remove(inter);
						}
					}

					interfaces = (Type[]) tmpInterfaces.ToArray(typeof(Type));
				}

				RegisterMixinMethodsAndProperties(emitter, ref methods, ref propsToGenerate, ref eventToGenerates);

				options.Hook.MethodsInspected();

				// Constructor

				ConstructorEmitter typeInitializer = GenerateStaticConstructor(emitter);

				if (!proxyTargetType.IsInterface)
				{
					CacheMethodTokens(emitter, MethodFinder.GetAllInstanceMethods(proxyTargetType,
					                                                              BindingFlags.Public | BindingFlags.Instance),
					                  typeInitializer);
				}

				CreateInitializeCacheMethodBody(proxyTargetType, methods, emitter, typeInitializer);
				FieldReference[] mixinFields = AddMixinFields(emitter);
				List<FieldReference> fields = new List<FieldReference>(mixinFields);
				fields.Add(interceptorsField);
				fields.Add(targetField);
				GenerateConstructors(emitter, baseType, fields.ToArray());
				// GenerateParameterlessConstructor(emitter, interceptorsField, baseType);

				// Implement interfaces

				if (interfaces != null && interfaces.Length != 0)
				{
					foreach(Type inter in interfaces)
					{
						ImplementBlankInterface(targetType, inter, emitter, interceptorsField, typeInitializer);
					}
				}

				// Create invocation types

				foreach(MethodInfo method in methods)
				{
					CreateInvocationForMethod(emitter, method, proxyTargetType);
				}

				// Create methods overrides

				Dictionary<MethodInfo, MethodEmitter> method2Emitter = new Dictionary<MethodInfo, MethodEmitter>();

				foreach(MethodInfo method in methods)
				{
					if (method.IsSpecialName &&
					    (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ||
					     method.Name.StartsWith("add_") || method.Name.StartsWith("remove_")) ||
					    methodsToSkip.Contains(method))
					{
						continue;
					}

					NestedClassEmitter nestedClass = (NestedClassEmitter) method2Invocation[method];

					MethodEmitter newProxiedMethod = CreateProxiedMethod(
						targetType, method, emitter, nestedClass, interceptorsField, GetTargetRef(method, mixinFields, targetField),
						ConstructorVersion.WithTargetMethod, (MethodInfo) method2methodOnTarget[method]);

					ReplicateNonInheritableAttributes(method, newProxiedMethod);

					method2Emitter[method] = newProxiedMethod;
				}

				foreach(PropertyToGenerate propToGen in propsToGenerate)
				{
					if (propToGen.CanRead)
					{
						NestedClassEmitter nestedClass = (NestedClassEmitter) method2Invocation[propToGen.GetMethod];

						MethodAttributes atts = ObtainMethodAttributes(propToGen.GetMethod);

						MethodEmitter getEmitter = propToGen.Emitter.CreateGetMethod(atts);

						ImplementProxiedMethod(targetType, getEmitter,
						                       propToGen.GetMethod, emitter,
											   nestedClass, interceptorsField, GetTargetRef(propToGen.GetMethod, mixinFields, targetField),
						                       ConstructorVersion.WithTargetMethod,
						                       (MethodInfo) method2methodOnTarget[propToGen.GetMethod]);

						ReplicateNonInheritableAttributes(propToGen.GetMethod, getEmitter);

						// emitter.TypeBuilder.DefineMethodOverride(getEmitter.MethodBuilder, propToGen.GetMethod);
					}

					if (propToGen.CanWrite)
					{
						NestedClassEmitter nestedClass = (NestedClassEmitter) method2Invocation[propToGen.SetMethod];

						MethodAttributes atts = ObtainMethodAttributes(propToGen.SetMethod);

						MethodEmitter setEmitter = propToGen.Emitter.CreateSetMethod(atts);

						ImplementProxiedMethod(targetType, setEmitter,
						                       propToGen.SetMethod, emitter,
											   nestedClass, interceptorsField, GetTargetRef(propToGen.SetMethod, mixinFields, targetField),
						                       ConstructorVersion.WithTargetMethod,
						                       (MethodInfo) method2methodOnTarget[propToGen.SetMethod]);

						ReplicateNonInheritableAttributes(propToGen.SetMethod, setEmitter);

						// emitter.TypeBuilder.DefineMethodOverride(setEmitter.MethodBuilder, propToGen.SetMethod);
					}
				}


				foreach(EventToGenerate eventToGenerate in eventToGenerates)
				{
					NestedClassEmitter add_nestedClass = (NestedClassEmitter) method2Invocation[eventToGenerate.AddMethod];

					MethodAttributes add_atts = ObtainMethodAttributes(eventToGenerate.AddMethod);

					MethodEmitter addEmitter = eventToGenerate.Emitter.CreateAddMethod(add_atts);

					ImplementProxiedMethod(targetType, addEmitter,
					                       eventToGenerate.AddMethod, emitter,
										   add_nestedClass, interceptorsField, GetTargetRef(eventToGenerate.AddMethod, mixinFields, targetField),
					                       ConstructorVersion.WithTargetMethod,
					                       (MethodInfo) method2methodOnTarget[eventToGenerate.AddMethod]);

					ReplicateNonInheritableAttributes(eventToGenerate.AddMethod, addEmitter);


					NestedClassEmitter remove_nestedClass = (NestedClassEmitter) method2Invocation[eventToGenerate.RemoveMethod];

					MethodAttributes remove_atts = ObtainMethodAttributes(eventToGenerate.RemoveMethod);

					MethodEmitter removeEmitter = eventToGenerate.Emitter.CreateRemoveMethod(remove_atts);

					ImplementProxiedMethod(targetType, removeEmitter,
					                       eventToGenerate.RemoveMethod, emitter,
										   remove_nestedClass, interceptorsField, GetTargetRef(eventToGenerate.RemoveMethod, mixinFields, targetField),
					                       ConstructorVersion.WithTargetMethod,
					                       (MethodInfo) method2methodOnTarget[eventToGenerate.RemoveMethod]);

					ReplicateNonInheritableAttributes(eventToGenerate.RemoveMethod, removeEmitter);
				}

				ImplementGetObjectData(emitter, interceptorsField, mixinFields, interfaces);

				// Complete Initialize 

				CompleteInitCacheMethod(typeInitializer.CodeBuilder);

				// Crosses fingers and build type

				generatedType = emitter.BuildType();
				InitializeStaticFields (generatedType);

				/*foreach (MethodInfo m in TypeFinder.GetMethods(generatedType, BindingFlags.Instance | BindingFlags.Public))
				{
					ParameterInfo[] parameters = m.GetParameters();

					// Console.WriteLine(m.Name);

					for (int i = 0; i < parameters.Length; i++)
					{
						ParameterInfo paramInfo = parameters[i];

						// Console.WriteLine("{0} {1} {2} {3}", paramInfo.Name, paramInfo.ParameterType, paramInfo.Attributes, paramInfo.Position);
						// Console.WriteLine("{0} {1} {2} {3}", paramInfo2.Name, paramInfo2.ParameterType, paramInfo2.Attributes, paramInfo2.Position);
					}
				}
				*/

				AddToCache(cacheKey, generatedType);
			}
			finally
			{
				rwlock.ReleaseWriterLock();
			}

			return generatedType;
		}
		private PropertyToGenerate[] CollectProperties(
			ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter)
		{
			ArrayList toGenerateList = new ArrayList();

			BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

			PropertyInfo[] properties = type.GetProperties(flags);

			foreach(PropertyInfo propInfo in properties)
			{
				bool generateReadable, generateWritable;

				generateWritable = generateReadable = false;

				MethodInfo setMethod, getMethod;
				setMethod = getMethod = null;

				if (propInfo.CanRead)
				{
					getMethod = propInfo.GetGetMethod(true);

					if (IsAccessible(getMethod) && AcceptMethod(getMethod, onlyVirtuals))
					{
						methodList.Add(getMethod);
						generateReadable = true;
					}
				}

				if (propInfo.CanWrite)
				{
					setMethod = propInfo.GetSetMethod(true);

					if (IsAccessible(setMethod) && AcceptMethod(setMethod, onlyVirtuals))
					{
						methodList.Add(setMethod);
						generateWritable = true;
					}
				}

				if (!generateWritable && !generateReadable)
				{
					continue;
				}

				PropertyAttributes atts = ObtainPropertyAttributes(propInfo);

				PropertyEmitter propEmitter = emitter.CreateProperty(propInfo.Name, atts, propInfo.PropertyType);

				PropertyToGenerate propToGenerate =
					new PropertyToGenerate(generateReadable, generateWritable, propEmitter, getMethod, setMethod);

				toGenerateList.Add(propToGenerate);
			}

			return (PropertyToGenerate[]) toGenerateList.ToArray(typeof(PropertyToGenerate));
		}
		protected MethodInfo[] CollectMethodsAndProperties(
			ClassEmitter emitter,
			Type targetType,
			bool onlyVirtuals,
			out PropertyToGenerate[] propsToGenerate,
			out EventToGenerate[] eventsToGenerate)
		{
			ArrayList methodsList = new ArrayList();

			CollectMethodsToProxy(methodsList, targetType, onlyVirtuals);
			CollectPropertyMethodsToProxy(methodsList, targetType, onlyVirtuals, emitter, out propsToGenerate);
			CollectEventMethodsToProxy(methodsList, targetType, onlyVirtuals, emitter, out eventsToGenerate);
			return (MethodInfo[]) methodsList.ToArray(typeof(MethodInfo));
		}
		protected MethodInfo[] CollectMethodsAndProperties(
			ClassEmitter emitter,
			Type targetType,
			out PropertyToGenerate[] propsToGenerate,
			out EventToGenerate[] eventsToGenerate)
		{
			bool onlyVirtuals = CanOnlyProxyVirtual();

			return CollectMethodsAndProperties(emitter, targetType, onlyVirtuals, out propsToGenerate, out eventsToGenerate);
		}
		protected void CollectPropertyMethodsToProxy(
			ArrayList methodList, Type type, bool onlyVirtuals, ClassEmitter emitter, out PropertyToGenerate[] propsToGenerate)
		{
			if (type.IsInterface)
			{
				ArrayList toGenerateList = new ArrayList();

				toGenerateList.AddRange(CollectProperties(methodList, type, onlyVirtuals, emitter));

				Type[] typeChain = type.FindInterfaces(new TypeFilter(NoFilter), null);

				foreach(Type interType in typeChain)
				{
					toGenerateList.AddRange(CollectProperties(methodList, interType, onlyVirtuals, emitter));
				}

				propsToGenerate = (PropertyToGenerate[]) toGenerateList.ToArray(typeof(PropertyToGenerate));
			}
			else
			{
				propsToGenerate = CollectProperties(methodList, type, onlyVirtuals, emitter);
			}
		}
Beispiel #6
0
		protected void RegisterMixinMethodsAndProperties(ClassEmitter emitter, ref MethodInfo[] methods, ref PropertyToGenerate[] propsToGenerate, ref EventToGenerate[] eventsToGenerate)
		{
			List<MethodInfo> withMixinMethods = new List<MethodInfo>(methods);
			List<PropertyToGenerate> withMixinProperties = null;
			List<EventToGenerate> withMixinEvents = null;

			foreach (Type mixinInterface in ProxyGenerationOptions.MixinData.MixinInterfacesAndPositions.Keys)
			{
				PropertyToGenerate[] mixinPropsToGenerate;
				EventToGenerate[] mixinEventsToGenerate;
				MethodInfo[] mixinMethods = CollectMethodsAndProperties(emitter, mixinInterface, false,
																		out mixinPropsToGenerate, out mixinEventsToGenerate);
				foreach (MethodInfo mixinMethod in mixinMethods)
				{
					if (!method2MixinType.ContainsKey(mixinMethod))
					{
						method2MixinType[mixinMethod] = mixinInterface;
						withMixinMethods.Add(mixinMethod);
					}
				}

				if (mixinPropsToGenerate.Length > 0)
				{
					if (withMixinProperties == null)
					{
						withMixinProperties = new List<PropertyToGenerate>(propsToGenerate);
					}
					withMixinProperties.AddRange(mixinPropsToGenerate);
				}

				if (mixinEventsToGenerate.Length > 0)
				{
					if (withMixinEvents == null)
					{
						withMixinEvents = new List<EventToGenerate>(eventsToGenerate);
					}
					withMixinEvents.AddRange(mixinEventsToGenerate);
				}
			}

			if (withMixinMethods != null)
			{
				methods = withMixinMethods.ToArray();
			}

			if (withMixinProperties != null)
			{
				propsToGenerate = withMixinProperties.ToArray();
			}

			if (withMixinEvents != null)
			{
				eventsToGenerate = withMixinEvents.ToArray();
			}
		}