/// <summary> /// Captures the proxy holder associated with this instance. /// </summary> void CaptureProxy() { if (!_ProxyCaptured) { lock (ProxyGenerator.ProxyLock) { _ProxyHolder = ProxyGenerator.ProxyHolders.Find(_EntityType); } _ProxyCaptured = true; if (_ProxyHolder != null) { _EntityType = _ProxyHolder.ProxyType.BaseType; } } }
/// <summary> /// Returns the proxy holder associated with the given map, creating and instance if it /// was not created yet. Returns null if no proxy type is needed because the type of the /// managed entities contains no lazy properties. /// </summary> internal static ProxyHolder Locate <T>(DataMap <T> map) where T : class { InitializeProxyGenerator(); var list = GetLazyProperties <T>(map); var name = GetProxyTypeName <T>(list); if (name == null) { return(null); } ProxyHolder holder = null; lock (ProxyLock) { // If the appropriate holder exists, just return it... holder = ProxyHolders.Where(x => x.ProxyType.Name == name).FirstOrDefault(); if (holder != null) { list.Clear(); return(holder); } // Otherwise, create a new one - we cannot yet add it as its type is not set yet... holder = new ProxyHolder(); // Capturing the lazy properties... foreach (var lazy in list) { holder.LazyProperties.Add(lazy); } // Preparing the builders... Type baseType = typeof(T); ILGenerator il = null; var proxyBuilder = _ModuleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit, baseType, null); // The fields that maintain whether the extended property is loaded or not... foreach (var lazy in holder.LazyProperties) { lazy.LazyCompletedFlag = proxyBuilder.DefineField(lazy.Name + COMPLETEDFLAG_SUFFIX, typeof(bool), FieldAttributes.Public); } // Replicating the constructors on the extended type... var baseCons = baseType.GetConstructors(TypeEx.InstancePublicAndHidden); foreach (var baseCon in baseCons) { var pars = baseCon.GetParameters(); var types = pars.Select(x => x.ParameterType).ToArray(); var proxyCon = proxyBuilder.DefineConstructor( baseCon.Attributes, baseCon.CallingConvention, types); il = proxyCon.GetILGenerator(); foreach (var element in holder.LazyProperties) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stfld, element.LazyCompletedFlag); } il.Emit(OpCodes.Ldarg_0); for (int i = 0; i < types.Length; i++) { il.Emit(OpCodes.Ldarg, i + 1); } il.Emit(OpCodes.Call, baseCon); il.Emit(OpCodes.Ret); } // Replicating the virtual properties on the extended type... var onProxySetter = typeof(ProxyGenerator).GetMethod("OnProxySetter", BindingFlags.Public | BindingFlags.Static); var onProxyGetter = typeof(ProxyGenerator).GetMethod("OnProxyGetter", BindingFlags.Public | BindingFlags.Static); // Treating the lazy properties... foreach (var lazy in holder.LazyProperties) { lazy.ExtendedProperty = proxyBuilder.DefineProperty(lazy.Name, lazy.OriginalProperty.Attributes, lazy.OriginalProperty.PropertyType, null); lazy.SourceBackProperty = proxyBuilder.DefineProperty(lazy.Name + SOURCEBACK_SUFFIX, lazy.OriginalProperty.Attributes, lazy.OriginalProperty.PropertyType, null); // The getter... if (lazy.OriginalGetter != null && lazy.OriginalGetter.IsVirtual && !lazy.OriginalGetter.IsPrivate) { var sourceBackMethod = proxyBuilder.DefineMethod("get_" + lazy.SourceBackProperty.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, lazy.SourceBackProperty.PropertyType, null); il = sourceBackMethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, lazy.OriginalGetter); il.Emit(OpCodes.Ret); ((PropertyBuilder)lazy.SourceBackProperty).SetGetMethod(sourceBackMethod); var extendedMethod = proxyBuilder.DefineMethod("get_" + lazy.ExtendedProperty.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, lazy.ExtendedProperty.PropertyType, null); il = extendedMethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, lazy.ExtendedProperty.Name); il.Emit(OpCodes.Call, onProxyGetter); il.Emit(OpCodes.Ret); ((PropertyBuilder)lazy.ExtendedProperty).SetGetMethod(extendedMethod); } // The setter... if (lazy.OriginalSetter != null && lazy.OriginalSetter.IsVirtual && !lazy.OriginalSetter.IsPrivate) { var sourceBackMethod = proxyBuilder.DefineMethod("set_" + lazy.SourceBackProperty.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, null, new[] { lazy.SourceBackProperty.PropertyType }); il = sourceBackMethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, lazy.OriginalSetter); il.Emit(OpCodes.Ret); ((PropertyBuilder)lazy.SourceBackProperty).SetSetMethod(sourceBackMethod); var extendedMethod = proxyBuilder.DefineMethod("Set_" + lazy.ExtendedProperty.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, null, new[] { lazy.ExtendedProperty.PropertyType }); il = extendedMethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldstr, lazy.ExtendedProperty.Name); il.Emit(OpCodes.Call, onProxySetter); il.Emit(OpCodes.Ret); ((PropertyBuilder)lazy.ExtendedProperty).SetSetMethod(extendedMethod); } } // Generating the type... holder.ProxyType = proxyBuilder.CreateType(); // Before releasing the lock let's cache some relevant information... var type = holder.ProxyType; foreach (var lazy in holder.LazyProperties) { lazy.LazyCompletedFlag = type.GetField(lazy.LazyCompletedFlag.Name, TypeEx.InstancePublicAndHidden); lazy.ExtendedProperty = type.GetProperty(lazy.ExtendedProperty.Name, TypeEx.InstancePublicAndHidden); lazy.ExtendedGetter = lazy.ExtendedProperty == null ? null : lazy.ExtendedProperty.GetGetMethod(nonPublic: true); lazy.ExtendedSetter = lazy.ExtendedProperty == null ? null : lazy.ExtendedProperty.GetSetMethod(nonPublic: true); lazy.SourceBackProperty = type.GetProperty(lazy.SourceBackProperty.Name, TypeEx.InstancePublicAndHidden); lazy.SourceBackGetter = lazy.SourceBackProperty == null ? null : lazy.SourceBackProperty.GetGetMethod(nonPublic: true); lazy.SourceBackSetter = lazy.SourceBackProperty == null ? null : lazy.SourceBackProperty.GetSetMethod(nonPublic: true); } // Now we can add the holder into the collection as we have set its type... ProxyHolders.Add(holder); } return(holder); }
/// <summary> /// Captures the proxy holder associated with this instance. /// </summary> void CaptureProxy() { if (!_ProxyCaptured) { lock (ProxyGenerator.ProxyLock) { _ProxyHolder = ProxyGenerator.ProxyHolders.Find(_EntityType); } _ProxyCaptured = true; if (_ProxyHolder != null) _EntityType = _ProxyHolder.ProxyType.BaseType; } }