EntityProxyFactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Objects / Internal / EntityProxyFactory.cs / 1599186 / EntityProxyFactory.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Metadata.Edm;
using System.Data.Objects.DataClasses; 
using System.Diagnostics;
using System.Globalization; 
using System.Linq; 
using System.Linq.Expressions;
using System.Reflection; 
using System.Reflection.Emit;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions; 
using System.Threading;
using System.Data.Common.Utils; 
using System.Runtime.CompilerServices; 

namespace System.Data.Objects.Internal 
{
    /// 
    /// Factory for creating proxy classes that can intercept calls to a class' members.
    ///  
    internal class EntityProxyFactory
    { 
        private const string ProxyTypeNameFormat = "System.Data.Entity.DynamicProxies.{0}_{1}"; 
        internal const string ResetFKSetterFlagFieldName = "_resetFKSetterFlag";
        internal const string CompareByteArraysFieldName = "_compareByteArrays"; 

        /// 
        /// A hook such that test code can change the AssemblyBuilderAccess of the
        /// proxy assembly through reflection into the EntityProxyFactory. 
        /// 
        private static AssemblyBuilderAccess s_ProxyAssemblyBuilderAccess = AssemblyBuilderAccess.Run; 
        ///  
        /// Dictionary of proxy class type information, keyed by the pair of the CLR type and EntityType CSpaceName of the type being proxied.
        /// A null value for a particular EntityType name key records the fact that 
        /// no proxy Type could be created for the specified type.
        /// 
        private static Dictionary, EntityProxyTypeInfo> s_ProxyNameMap = new Dictionary, EntityProxyTypeInfo>();
        ///  
        /// Dictionary of proxy class type information, keyed by the proxy type
        ///  
        private static Dictionary s_ProxyTypeMap = new Dictionary(); 
        private static Dictionary s_ModuleBuilders = new Dictionary();
        private static ReaderWriterLockSlim s_TypeMapLock = new ReaderWriterLockSlim(); 

        /// 
        /// The runtime assembly of the proxy types.
        /// This is not the same as the AssemblyBuilder used to create proxy types. 
        /// 
        private static HashSet ProxyRuntimeAssemblies = new HashSet(); 
 
        private static ModuleBuilder GetDynamicModule(EntityType ospaceEntityType)
        { 
            Assembly assembly = ospaceEntityType.ClrType.Assembly;
            ModuleBuilder moduleBuilder;
            if (!s_ModuleBuilders.TryGetValue(assembly, out moduleBuilder))
            { 
                AssemblyName assemblyName = new AssemblyName(String.Format(CultureInfo.InvariantCulture, "EntityFrameworkDynamicProxies-{0}", assembly.FullName));
                assemblyName.Version = new Version(1, 0, 0, 0); 
 
                // Mark assembly as security transparent, meaning it cannot cause an elevation of privilege.
                // This also means the assembly cannot satisfy a link demand. Instead link demands become full demands. 
                ConstructorInfo securityTransparentAttributeConstructor = typeof(SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes);

                // Mark assembly with [SecurityRules(SecurityRuleSet.Level1)]. In memory, the assembly will inherit
                // this automatically from SDE, but when persisted it needs this attribute to be considered Level1. 
                ConstructorInfo securityRulesAttributeConstructor = typeof(SecurityRulesAttribute).GetConstructor(new Type[] { typeof(SecurityRuleSet) });
 
                CustomAttributeBuilder[] attributeBuilders = new CustomAttributeBuilder[] { 
                    new CustomAttributeBuilder(securityTransparentAttributeConstructor, new object[0]),
                    new CustomAttributeBuilder(securityRulesAttributeConstructor, new object[1] { SecurityRuleSet.Level1 }) 
                };

                AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, s_ProxyAssemblyBuilderAccess, attributeBuilders);
 
                if (s_ProxyAssemblyBuilderAccess == AssemblyBuilderAccess.RunAndSave)
                { 
                    // Make the module persistable if the AssemblyBuilderAccess is changed to be RunAndSave. 
                    moduleBuilder = assemblyBuilder.DefineDynamicModule("EntityProxyModule", "EntityProxyModule.dll");
                } 
                else
                {
                    moduleBuilder = assemblyBuilder.DefineDynamicModule("EntityProxyModule");
                } 

                s_ModuleBuilders.Add(assembly, moduleBuilder); 
            } 
            return moduleBuilder;
        } 

        internal static bool TryGetProxyType(Type clrType, string entityTypeName, out EntityProxyTypeInfo proxyTypeInfo)
        {
            s_TypeMapLock.EnterReadLock(); 
            try
            { 
                return s_ProxyNameMap.TryGetValue(new Tuple(clrType, entityTypeName), out proxyTypeInfo); 
            }
            finally 
            {
                s_TypeMapLock.ExitReadLock();
            }
        } 

        internal static bool TryGetProxyType(Type proxyType, out EntityProxyTypeInfo proxyTypeInfo) 
        { 
            s_TypeMapLock.EnterReadLock();
            try 
            {
                return s_ProxyTypeMap.TryGetValue(proxyType, out proxyTypeInfo);
            }
            finally 
            {
                s_TypeMapLock.ExitReadLock(); 
            } 
        }
 
        internal static bool TryGetProxyWrapper(object instance, out IEntityWrapper wrapper)
        {
            Debug.Assert(instance != null, "the instance should not be null");
            wrapper = null; 
            EntityProxyTypeInfo proxyTypeInfo;
            if (IsProxyType(instance.GetType()) && 
                TryGetProxyType(instance.GetType(), out proxyTypeInfo)) 
            {
                wrapper = proxyTypeInfo.GetEntityWrapper(instance); 
            }
            return wrapper != null;
        }
 
        /// 
        /// Return proxy type information for the specified O-Space EntityType. 
        ///  
        /// 
        /// EntityType in O-Space that represents the CLR type to be proxied. 
        /// Must not be null.
        /// 
        /// 
        /// A non-null EntityProxyTypeInfo instance that contains information about the type of proxy for 
        /// the specified O-Space EntityType; or null if no proxy can be created for the specified type.
        ///  
        internal static EntityProxyTypeInfo GetProxyType(ClrEntityType ospaceEntityType) 
        {
            Debug.Assert(ospaceEntityType != null, "ospaceEntityType must be non-null"); 
            Debug.Assert(ospaceEntityType.DataSpace == DataSpace.OSpace, "ospaceEntityType.DataSpace must be OSpace");

            EntityProxyTypeInfo proxyTypeInfo = null;
 
            // Check if an entry for the proxy type already exists.
            if (TryGetProxyType(ospaceEntityType.ClrType, ospaceEntityType.CSpaceTypeName, out proxyTypeInfo)) 
            { 
                if (proxyTypeInfo != null)
                { 
                    proxyTypeInfo.ValidateType(ospaceEntityType);
                }
                return proxyTypeInfo;
            } 

            // No entry found, may need to create one. 
            // Acquire an upgradeable read lock so that: 
            // 1. Other readers aren't blocked while the second existence check is performed.
            // 2. Other threads that may have also detected the absence of an entry block while the first thread handles proxy type creation. 

            s_TypeMapLock.EnterUpgradeableReadLock();
            try
            { 
                return TryCreateProxyType(ospaceEntityType);
            } 
            finally 
            {
                s_TypeMapLock.ExitUpgradeableReadLock(); 
            }
        }

        ///  
        /// A mechanism to lookup AssociationType metadata for proxies for a given entity and association information
        ///  
        /// The entity instance used to lookup the proxy type 
        /// The name of the relationship (FullName or Name)
        /// Target role of the relationship 
        /// The AssociationType for that property
        /// True if an AssociationType is found in proxy metadata, false otherwise
        internal static bool TryGetAssociationTypeFromProxyInfo(IEntityWrapper wrappedEntity, string relationshipName, string targetRoleName, out AssociationType associationType)
        { 
            EntityProxyTypeInfo proxyInfo = null;
            associationType = null; 
            return (EntityProxyFactory.TryGetProxyType(wrappedEntity.Entity.GetType(), out proxyInfo) && proxyInfo != null && 
                    proxyInfo.TryGetNavigationPropertyAssociationType(relationshipName, targetRoleName, out associationType));
        } 

        /// 
        /// Enumerate list of supplied O-Space EntityTypes,
        /// and generate a proxy type for each EntityType (if possible for the particular type). 
        /// 
        ///  
        /// Enumeration of O-Space EntityType objects. 
        /// Must not be null.
        /// In addition, the elements of the enumeration must not be null. 
        /// 
        internal static void TryCreateProxyTypes(IEnumerable ospaceEntityTypes)
        {
            Debug.Assert(ospaceEntityTypes != null, "ospaceEntityTypes must be non-null"); 

            // Acquire an upgradeable read lock for the duration of the enumeration so that: 
            // 1. Other readers aren't blocked while existence checks are performed. 
            // 2. Other threads that may have detected the absence of an entry block while the first thread handles proxy type creation.
 
            s_TypeMapLock.EnterUpgradeableReadLock();
            try
            {
                foreach (EntityType ospaceEntityType in ospaceEntityTypes) 
                {
                    Debug.Assert(ospaceEntityType != null, "Null EntityType element reference present in enumeration."); 
                    TryCreateProxyType(ospaceEntityType); 
                }
            } 
            finally
            {
                s_TypeMapLock.ExitUpgradeableReadLock();
            } 
        }
 
        private static EntityProxyTypeInfo TryCreateProxyType(EntityType ospaceEntityType) 
        {
            Debug.Assert(s_TypeMapLock.IsUpgradeableReadLockHeld, "EntityProxyTypeInfo.TryCreateProxyType method was called without first acquiring an upgradeable read lock from s_TypeMapLock."); 

            EntityProxyTypeInfo proxyTypeInfo;
            ClrEntityType clrEntityType = (ClrEntityType)ospaceEntityType;
 
            Tuple proxyIdentiy = new Tuple(clrEntityType.ClrType, clrEntityType.HashedDescription);
 
            if (!s_ProxyNameMap.TryGetValue(proxyIdentiy, out proxyTypeInfo) && CanProxyType(ospaceEntityType)) 
            {
                ModuleBuilder moduleBuilder = GetDynamicModule(ospaceEntityType); 
                proxyTypeInfo = BuildType(moduleBuilder, clrEntityType);

                s_TypeMapLock.EnterWriteLock();
                try 
                {
                    s_ProxyNameMap[proxyIdentiy] = proxyTypeInfo; 
                    if (proxyTypeInfo != null) 
                    {
                        // If there is a proxy type, create the reverse lookup 
                        s_ProxyTypeMap[proxyTypeInfo.ProxyType] = proxyTypeInfo;
                    }
                }
                finally 
                {
                    s_TypeMapLock.ExitWriteLock(); 
                } 
            }
 
            return proxyTypeInfo;
        }

        ///  
        /// Determine if the specified type represents a known proxy type.
        ///  
        ///  
        /// The Type to be examined.
        ///  
        /// 
        /// True if the type is a known proxy type; otherwise false.
        /// 
        internal static bool IsProxyType(Type type) 
        {
            Debug.Assert(type != null, "type is null, was this intended?"); 
            return type != null && ProxyRuntimeAssemblies.Contains(type.Assembly); 
        }
 
        /// 
        /// Return an enumerable of the current set of CLR proxy types.
        /// 
        ///  
        /// Enumerable of the current set of CLR proxy types.
        /// This value will never be null. 
        ///  
        /// 
        /// The enumerable is based on a shapshot of the current list of types. 
        /// 
        internal static IEnumerable GetKnownProxyTypes()
        {
            s_TypeMapLock.EnterReadLock(); 
            try
            { 
                var proxyTypes = from info in s_ProxyNameMap.Values 
                                 where info != null
                                 select info.ProxyType; 
                return proxyTypes.ToArray();
            }
            finally
            { 
                s_TypeMapLock.ExitReadLock();
            } 
        } 

        public Func CreateBaseGetter(Type declaringType, PropertyInfo propertyInfo) 
        {
            Debug.Assert(propertyInfo != null, "Null propertyInfo");

            ParameterExpression Object_Parameter = Expression.Parameter(typeof(object), "instance"); 
            Func nonProxyGetter = Expression.Lambda>(
                                    Expression.PropertyOrField( 
                                        Expression.Convert(Object_Parameter, declaringType), 
                                        propertyInfo.Name),
                                    Object_Parameter).Compile(); 

            string propertyName = propertyInfo.Name;
            return (entity) =>
            { 
                Type type = entity.GetType();
                if (IsProxyType(type)) 
                { 
                    object value;
                    if (TryGetBasePropertyValue(type, propertyName, entity, out value)) 
                    {
                        return value;
                    }
                } 
                return nonProxyGetter(entity);
            }; 
        } 

        private static bool TryGetBasePropertyValue(Type proxyType, string propertyName, object entity, out object value) 
        {
            EntityProxyTypeInfo typeInfo;
            value = null;
            if (TryGetProxyType(proxyType, out typeInfo) && typeInfo.ContainsBaseGetter(propertyName)) 
            {
                value = typeInfo.BaseGetter(entity, propertyName); 
                return true; 
            }
            return false; 
        }

        public Action CreateBaseSetter(Type declaringType, PropertyInfo propertyInfo)
        { 
            Debug.Assert(propertyInfo != null, "Null propertyInfo");
 
            Action nonProxySetter = LightweightCodeGenerator.CreateNavigationPropertySetter(declaringType, propertyInfo); 

            string propertyName = propertyInfo.Name; 
            return (entity, value) =>
            {
                Type type = entity.GetType();
                if (IsProxyType(type)) 
                {
                    if (TrySetBasePropertyValue(type, propertyName, entity, value)) 
                    { 
                        return;
                    } 
                }
                nonProxySetter(entity, value);
            };
        } 

        private static bool TrySetBasePropertyValue(Type proxyType, string propertyName, object entity, object value) 
        { 
            EntityProxyTypeInfo typeInfo;
            if (TryGetProxyType(proxyType, out typeInfo) && typeInfo.ContainsBaseSetter(propertyName)) 
            {
                typeInfo.BaseSetter(entity, propertyName, value);
                return true;
            } 
            return false;
        } 
 
        /// 
        /// Build a CLR proxy type for the supplied EntityType. 
        /// 
        /// 
        /// EntityType in O-Space that represents the CLR type to be proxied.
        ///  
        /// 
        /// EntityProxyTypeInfo object that contains the constructed proxy type, 
        /// along with any behaviors associated with that type; 
        /// or null if a proxy type cannot be constructed for the specified EntityType.
        ///  
        private static EntityProxyTypeInfo BuildType(ModuleBuilder moduleBuilder, ClrEntityType ospaceEntityType)
        {
            Debug.Assert(s_TypeMapLock.IsUpgradeableReadLockHeld, "EntityProxyTypeInfo.BuildType method was called without first acquiring an upgradeable read lock from s_TypeMapLock.");
 
            EntityProxyTypeInfo proxyTypeInfo;
 
            ProxyTypeBuilder proxyTypeBuilder = new ProxyTypeBuilder(ospaceEntityType); 
            Type proxyType = proxyTypeBuilder.CreateType(moduleBuilder);
 
            if (proxyType != null)
            {
                // Set the runtime assembly of the proxy types if it hasn't already been set.
                // This is used by the IsProxyType method. 
                Assembly typeAssembly = proxyType.Assembly;
                if (!ProxyRuntimeAssemblies.Contains(typeAssembly)) 
                { 
                    ProxyRuntimeAssemblies.Add(typeAssembly);
                    AddAssemblyToResolveList(typeAssembly); 
                }

                proxyTypeInfo = new EntityProxyTypeInfo(proxyType, ospaceEntityType,
                    proxyTypeBuilder.CreateInitalizeCollectionMethod(proxyType), 
                    proxyTypeBuilder.BaseGetters, proxyTypeBuilder.BaseSetters);
 
                foreach (EdmMember member in proxyTypeBuilder.LazyLoadMembers) 
                {
                    InterceptMember(member, proxyType, proxyTypeInfo); 
                }

                SetResetFKSetterFlagDelegate(proxyType, proxyTypeInfo);
                SetCompareByteArraysDelegate(proxyType, proxyTypeInfo); 
            }
            else 
            { 
                proxyTypeInfo = null;
            } 

            return proxyTypeInfo;
        }
 
        /// 
        /// In order for deserialization of proxy objects to succeed in this AppDomain, 
        /// an assembly resolve handler must be added to the AppDomain to resolve the dynamic assembly, 
        /// since it is not present in a location discoverable by fusion.
        ///  
        /// Proxy assembly to be resolved.
        [SecuritySafeCritical]
        private static void AddAssemblyToResolveList(Assembly assembly)
        { 
            if (ProxyRuntimeAssemblies.Contains(assembly)) // If the assembly is not a known proxy assembly, ignore it.
            { 
                ResolveEventHandler resolveHandler = new ResolveEventHandler((sender, args) => args.Name == assembly.FullName ? assembly : null); 
                AppDomain.CurrentDomain.AssemblyResolve += resolveHandler;
            } 
        }

        /// 
        /// Construct an interception delegate for the specified proxy member. 
        /// 
        ///  
        /// EdmMember that specifies the member to be intercepted. 
        /// 
        ///  
        /// Type of the proxy.
        /// 
        /// 
        /// LazyLoadBehavior object that supplies the behavior to load related ends. 
        /// 
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] 
        private static void InterceptMember(EdmMember member, Type proxyType, EntityProxyTypeInfo proxyTypeInfo) 
        {
            PropertyInfo property = EntityUtil.GetTopProperty(proxyType, member.Name); 
            Debug.Assert(property != null, String.Format(CultureInfo.CurrentCulture, "Expected property {0} to be defined on proxy type {1}", member.Name, proxyType.FullName));

            FieldInfo interceptorField = proxyType.GetField(LazyLoadImplementor.GetInterceptorFieldName(member.Name), BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic);
            Debug.Assert(interceptorField != null, String.Format(CultureInfo.CurrentCulture, "Expected interceptor field for property {0} to be defined on proxy type {1}", member.Name, proxyType.FullName)); 

            Delegate interceptorDelegate = typeof(LazyLoadBehavior).GetMethod("GetInterceptorDelegate", BindingFlags.NonPublic | BindingFlags.Static). 
                MakeGenericMethod(proxyType, property.PropertyType). 
                Invoke(null, new object[] { member, proxyTypeInfo.EntityWrapperDelegate }) as Delegate;
 
            AssignInterceptionDelegate(interceptorDelegate, interceptorField);
        }

        ///  
        /// Set the interceptor on a proxy member.
        ///  
        ///  
        /// Delegate to be set
        ///  
        /// 
        /// Field define on the proxy type to store the reference to the interception delegate.
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2128")] 
        [SecuritySafeCritical]
        [ReflectionPermission(SecurityAction.Assert, MemberAccess = true)] 
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] 
        private static void AssignInterceptionDelegate(Delegate interceptorDelegate, FieldInfo interceptorField)
        { 
            interceptorField.SetValue(null, interceptorDelegate);
        }

        ///  
        /// Sets a delegate onto the _resetFKSetterFlag field such that it can be executed to make
        /// a call into the state manager to reset the InFKSetter flag. 
        ///  
        private static void SetResetFKSetterFlagDelegate(Type proxyType, EntityProxyTypeInfo proxyTypeInfo)
        { 
            var resetFKSetterFlagField = proxyType.GetField(ResetFKSetterFlagFieldName, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic);
            Debug.Assert(resetFKSetterFlagField != null, "Expected resetFKSetterFlagField to be defined on the proxy type.");

            var resetFKSetterFlagDelegate = GetResetFKSetterFlagDelegate(proxyTypeInfo.EntityWrapperDelegate); 

            AssignInterceptionDelegate(resetFKSetterFlagDelegate, resetFKSetterFlagField); 
        } 

        ///  
        /// Returns the delegate that takes a proxy instance and uses it to reset the InFKSetter flag maintained
        /// by the state manager of the context associated with the proxy instance.
        /// 
        private static Action GetResetFKSetterFlagDelegate(Func getEntityWrapperDelegate) 
        {
            return (proxy) => 
            { 
                if (getEntityWrapperDelegate != null)
                { 
                    ResetFKSetterFlag(getEntityWrapperDelegate(proxy));
                }
            };
        } 

        ///  
        /// Called in the finally clause of each overridden property setter to ensure that the flag 
        /// indicating that we are in an FK setter is cleared.  Note that the wrapped entity is passed as
        /// an obejct becayse IEntityWrapper is an internal type and is therefore not accessable to 
        /// the proxy type.  Once we're in the framework it is cast back to an IEntityWrapper.
        /// 
        private static void ResetFKSetterFlag(object wrappedEntityAsObject)
        { 
            Debug.Assert(wrappedEntityAsObject == null || wrappedEntityAsObject is IEntityWrapper, "wrappedEntityAsObject must be an IEntityWrapper");
            var wrappedEntity = (IEntityWrapper)wrappedEntityAsObject; // We want an exception if the cast fails. 
            if (wrappedEntity != null && wrappedEntity.Context != null) 
            {
                wrappedEntity.Context.ObjectStateManager.InFKSetter = false; 
            }
        }

        ///  
        /// Sets a delegate onto the _compareByteArrays field such that it can be executed to check
        /// whether two byte arrays are the same by value comparison. 
        ///  
        private static void SetCompareByteArraysDelegate(Type proxyType, EntityProxyTypeInfo proxyTypeInfo)
        { 
            var compareByteArraysField = proxyType.GetField(CompareByteArraysFieldName, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic);
            Debug.Assert(compareByteArraysField != null, "Expected compareByteArraysField to be defined on the proxy type.");

            AssignInterceptionDelegate(new Func(ByValueEqualityComparer.Default.Equals), compareByteArraysField); 
        }
 
        ///  
        /// Return boolean that specifies if the specified type can be proxied.
        ///  
        /// O-space EntityType
        /// 
        /// True if the class is not abstract or sealed, does not implement IEntityWithRelationships,
        /// and has a public or protected default constructor; otherwise false. 
        /// 
        ///  
        /// While it is technically possible to derive from an abstract type 
        /// in order to create a proxy, we avoid this so that the proxy type
        /// has the same "concreteness" of the type being proxied. 
        /// The check for IEntityWithRelationships ensures that codegen'ed
        /// entities that derive from EntityObject as well as properly
        /// constructed IPOCO entities will not be proxied.
        /// 
        /// 
        private static bool CanProxyType(EntityType ospaceEntityType) 
        { 
            TypeAttributes access = ospaceEntityType.ClrType.Attributes & TypeAttributes.VisibilityMask;
 
            ConstructorInfo ctor = ospaceEntityType.ClrType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, Type.EmptyTypes, null);
            bool accessableCtor = ctor != null && (((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) ||
                                                   ((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family) ||
                                                   ((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem)); 

            return (!(ospaceEntityType.Abstract || 
                     ospaceEntityType.ClrType.IsSealed || 
                     typeof(IEntityWithRelationships).IsAssignableFrom(ospaceEntityType.ClrType) ||
                     !accessableCtor) && 
                     access == TypeAttributes.Public);
        }

        private static bool CanProxyMethod(MethodInfo method) 
        {
            bool result = false; 
 
            if (method != null)
            { 
                MethodAttributes access = method.Attributes & MethodAttributes.MemberAccessMask;
                result = method.IsVirtual &&
                         !method.IsFinal &&
                         (access == MethodAttributes.Public || 
                          access == MethodAttributes.Family ||
                          access == MethodAttributes.FamORAssem); 
            } 

            return result; 
        }

        internal static bool CanProxyGetter(PropertyInfo clrProperty)
        { 
            Debug.Assert(clrProperty != null, "clrProperty should have a value");
            return CanProxyMethod(clrProperty.GetGetMethod(true)); 
        } 

        internal static bool CanProxySetter(PropertyInfo clrProperty) 
        {
            Debug.Assert(clrProperty != null, "clrProperty should have a value");
            return CanProxyMethod(clrProperty.GetSetMethod(true));
        } 

        private class ProxyTypeBuilder 
        { 
            private TypeBuilder _typeBuilder;
            private BaseProxyImplementor _baseImplementor; 
            private IPOCOImplementor _ipocoImplementor;
            private LazyLoadImplementor _lazyLoadImplementor;
            private DataContractImplementor _dataContractImplementor;
            private ISerializableImplementor _iserializableImplementor; 
            private ClrEntityType _ospaceEntityType;
            private ModuleBuilder _moduleBuilder; 
            private List _serializedFields = new List(3); 

            public ProxyTypeBuilder(ClrEntityType ospaceEntityType) 
            {
                _ospaceEntityType = ospaceEntityType;
                _baseImplementor = new BaseProxyImplementor();
                _ipocoImplementor = new IPOCOImplementor(ospaceEntityType); 
                _lazyLoadImplementor = new LazyLoadImplementor(ospaceEntityType);
                _dataContractImplementor = new DataContractImplementor(ospaceEntityType); 
                _iserializableImplementor = new ISerializableImplementor(ospaceEntityType); 
            }
 
            public Type BaseType
            {
                get { return _ospaceEntityType.ClrType; }
            } 

            public DynamicMethod CreateInitalizeCollectionMethod(Type proxyType) 
            { 
                return _ipocoImplementor.CreateInitalizeCollectionMethod(proxyType);
            } 

            public List BaseGetters
            {
                get 
                {
                    return _baseImplementor.BaseGetters; 
                } 
            }
 
            public List BaseSetters
            {
                get
                { 
                    return _baseImplementor.BaseSetters;
                } 
            } 

            public IEnumerable LazyLoadMembers 
            {
                get { return _lazyLoadImplementor.Members; }
            }
 
            public Type CreateType(ModuleBuilder moduleBuilder)
            { 
                _moduleBuilder = moduleBuilder; 
                bool hadProxyProperties = false;
 
                if (_iserializableImplementor.TypeIsSuitable)
                {
                    foreach (EdmMember member in _ospaceEntityType.Members)
                    { 
                        if (_ipocoImplementor.CanProxyMember(member) ||
                            _lazyLoadImplementor.CanProxyMember(member)) 
                        { 
                            PropertyInfo baseProperty = EntityUtil.GetTopProperty(BaseType, member.Name);
                            PropertyBuilder propertyBuilder = TypeBuilder.DefineProperty(member.Name, System.Reflection.PropertyAttributes.None, baseProperty.PropertyType, Type.EmptyTypes); 

                            if (!_ipocoImplementor.EmitMember(TypeBuilder, member, propertyBuilder, baseProperty, _baseImplementor))
                            {
                                EmitBaseSetter(TypeBuilder, propertyBuilder, baseProperty); 
                            }
                            if (!_lazyLoadImplementor.EmitMember(TypeBuilder, member, propertyBuilder, baseProperty, _baseImplementor)) 
                            { 
                                EmitBaseGetter(TypeBuilder, propertyBuilder, baseProperty);
                            } 

                            hadProxyProperties = true;
                        }
                    } 

                    if (_typeBuilder != null) 
                    { 
                        _baseImplementor.Implement(TypeBuilder, RegisterInstanceField);
                        _iserializableImplementor.Implement(TypeBuilder, _serializedFields); 
                    }
                }

                return hadProxyProperties ? TypeBuilder.CreateType() : null; 
            }
 
            private TypeBuilder TypeBuilder 
            {
                get 
                {
                    if (_typeBuilder == null)
                    {
                        TypeAttributes proxyTypeAttributes = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed; 
                        if ((BaseType.Attributes & TypeAttributes.Serializable) == TypeAttributes.Serializable)
                        { 
                            proxyTypeAttributes |= TypeAttributes.Serializable; 
                        }
 
                        // If the type as a long name, then use only the first part of it so that there is no chance that the generated
                        // name will be too long.  Note that the full name always gets used to compute the hash.
                        string baseName = BaseType.Name.Length <= 20 ? BaseType.Name : BaseType.Name.Substring(0, 20);
                        string proxyTypeName = String.Format(CultureInfo.InvariantCulture, ProxyTypeNameFormat, baseName, _ospaceEntityType.HashedDescription); 

                        _typeBuilder = _moduleBuilder.DefineType(proxyTypeName, proxyTypeAttributes, BaseType, _ipocoImplementor.Interfaces); 
                        _typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName); 

                        Action registerField = RegisterInstanceField; 
                        _ipocoImplementor.Implement(_typeBuilder, registerField);
                        _lazyLoadImplementor.Implement(_typeBuilder, registerField);

                        // WCF data contract serialization is not compatible with types that implement ISerializable. 
                        if (!_iserializableImplementor.TypeImplementsISerializable)
                        { 
                            _dataContractImplementor.Implement(_typeBuilder, registerField); 
                        }
                    } 
                    return _typeBuilder;
                }
            }
 
            private void EmitBaseGetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty)
            { 
                if (CanProxyGetter(baseProperty)) 
                {
                    MethodInfo baseGetter = baseProperty.GetGetMethod(true); 
                    const MethodAttributes getterAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
                    MethodAttributes getterAccess = baseGetter.Attributes & MethodAttributes.MemberAccessMask;

                    // Define a property getter override in the proxy type 
                    MethodBuilder getterBuilder = typeBuilder.DefineMethod("get_" + baseProperty.Name, getterAccess | getterAttributes, baseProperty.PropertyType, Type.EmptyTypes);
                    ILGenerator gen = getterBuilder.GetILGenerator(); 
 
                    gen.Emit(OpCodes.Ldarg_0);
                    gen.Emit(OpCodes.Call, baseGetter); 
                    gen.Emit(OpCodes.Ret);

                    propertyBuilder.SetGetMethod(getterBuilder);
                } 
            }
 
            private void EmitBaseSetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty) 
            {
                if (CanProxySetter(baseProperty)) 
                {

                    MethodInfo baseSetter = baseProperty.GetSetMethod(true); ;
                    const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual; 
                    MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask;
 
                    MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType }); 
                    ILGenerator generator = setterBuilder.GetILGenerator();
                    generator.Emit(OpCodes.Ldarg_0); 
                    generator.Emit(OpCodes.Ldarg_1);
                    generator.Emit(OpCodes.Call, baseSetter);
                    generator.Emit(OpCodes.Ret);
                    propertyBuilder.SetSetMethod(setterBuilder); 
                }
            } 
 
            private void RegisterInstanceField(FieldBuilder field, bool serializable)
            { 
                if (serializable)
                {
                    _serializedFields.Add(field);
                } 
                else
                { 
                    MarkAsNotSerializable(field); 
                }
            } 

            private static readonly ConstructorInfo s_NonSerializedAttributeConstructor = typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes);
            private static readonly ConstructorInfo s_IgnoreDataMemberAttributeConstructor = typeof(IgnoreDataMemberAttribute).GetConstructor(Type.EmptyTypes);
            private static readonly ConstructorInfo s_XmlIgnoreAttributeConstructor = typeof(System.Xml.Serialization.XmlIgnoreAttribute).GetConstructor(Type.EmptyTypes); 

            private static void MarkAsNotSerializable(FieldBuilder field) 
            { 
                object[] emptyArray = new object[0];
 
                field.SetCustomAttribute(new CustomAttributeBuilder(s_NonSerializedAttributeConstructor, emptyArray));

                if (field.IsPublic)
                { 
                    field.SetCustomAttribute(new CustomAttributeBuilder(s_IgnoreDataMemberAttributeConstructor, emptyArray));
                    field.SetCustomAttribute(new CustomAttributeBuilder(s_XmlIgnoreAttributeConstructor, emptyArray)); 
                } 
            }
        } 
    }

    internal class LazyLoadImplementor
    { 
        HashSet _members;
 
        public LazyLoadImplementor(EntityType ospaceEntityType) 
        {
            CheckType(ospaceEntityType); 
        }

        public IEnumerable Members
        { 
            get { return _members; }
        } 
 
        private void CheckType(EntityType ospaceEntityType)
        { 
            _members = new HashSet();

            foreach (EdmMember member in ospaceEntityType.Members)
            { 
                PropertyInfo clrProperty = EntityUtil.GetTopProperty(ospaceEntityType.ClrType, member.Name);
                if (clrProperty != null && 
                    EntityProxyFactory.CanProxyGetter(clrProperty) && 
                    LazyLoadBehavior.IsLazyLoadCandidate(ospaceEntityType, member))
                { 
                    _members.Add(member);
                }
            }
        } 

        public bool CanProxyMember(EdmMember member) 
        { 
            return _members.Contains(member);
        } 

        public void Implement(TypeBuilder typeBuilder, Action registerField)
        {
            if (_members.Count > 0) 
            {
                // Add instance field to store IEntityWrapper instance 
                // The field is typed as object, for two reasons: 
                // 1. The practical one, IEntityWrapper is internal and not accessible from the dynamic assembly.
                // 2. We purposely want the wrapper field to be opaque on the proxy type. 
                FieldBuilder wrapperField = typeBuilder.DefineField(EntityProxyTypeInfo.EntityWrapperFieldName, typeof(object), FieldAttributes.Public);
                registerField(wrapperField, false);
            }
        } 

        public bool EmitMember(TypeBuilder typeBuilder, EdmMember member, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, BaseProxyImplementor baseImplementor) 
        { 
            if (_members.Contains(member))
            { 
                MethodInfo baseGetter = baseProperty.GetGetMethod(true);
                const MethodAttributes getterAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
                MethodAttributes getterAccess = baseGetter.Attributes & MethodAttributes.MemberAccessMask;
 
                // Define field to store interceptor Func
                // Signature of interceptor Func delegate is as follows: 
                // 
                //    bool intercept(ProxyType proxy, PropertyType propertyValue)
                // 
                // where
                //     PropertyType is the type of the Property, such as ICollection,
                //     ProxyType is the type of the proxy object,
                //     propertyValue is the value returned from the proxied type's property getter. 

                Type interceptorType = typeof(Func<,,>).MakeGenericType(typeBuilder, baseProperty.PropertyType, typeof(bool)); 
                MethodInfo interceptorInvoke = TypeBuilder.GetMethod(interceptorType, typeof(Func<,,>).GetMethod("Invoke")); 
                FieldBuilder interceptorField = typeBuilder.DefineField(GetInterceptorFieldName(baseProperty.Name), interceptorType, FieldAttributes.Private | FieldAttributes.Static);
 
                // Define a property getter override in the proxy type
                MethodBuilder getterBuilder = typeBuilder.DefineMethod("get_" + baseProperty.Name, getterAccess | getterAttributes, baseProperty.PropertyType, Type.EmptyTypes);
                ILGenerator generator = getterBuilder.GetILGenerator();
 
                // Emit instructions for the following call:
                //   T value = base.SomeProperty; 
                //   if(this._interceptorForSomeProperty(this, value)) 
                //   {  return value; }
                //   return base.SomeProperty; 
                // where _interceptorForSomeProperty represents the interceptor Func field.

                Label lableTrue = generator.DefineLabel();
                generator.DeclareLocal(baseProperty.PropertyType);       // T value 
                generator.Emit(OpCodes.Ldarg_0);            // call base.SomeProperty
                generator.Emit(OpCodes.Call, baseGetter); // call to base property getter 
                generator.Emit(OpCodes.Stloc_0);            // value = result 
                generator.Emit(OpCodes.Ldarg_0);            // load this
                generator.Emit(OpCodes.Ldfld, interceptorField); // load this._interceptor 
                generator.Emit(OpCodes.Ldarg_0);            // load this
                generator.Emit(OpCodes.Ldloc_0);            // load value
                generator.Emit(OpCodes.Callvirt, interceptorInvoke); // call to interceptor delegate with (this, value)
                generator.Emit(OpCodes.Brtrue_S, lableTrue); // if true, just return 
                generator.Emit(OpCodes.Ldarg_0); // else, call the base propertty getter again
                generator.Emit(OpCodes.Call, baseGetter); // call to base property getter 
                generator.Emit(OpCodes.Ret); 
                generator.MarkLabel(lableTrue);
                generator.Emit(OpCodes.Ldloc_0); 
                generator.Emit(OpCodes.Ret);

                propertyBuilder.SetGetMethod(getterBuilder);
 
                baseImplementor.AddBasePropertyGetter(baseProperty);
                return true; 
            } 
            return false;
        } 


        internal static string GetInterceptorFieldName(string memberName)
        { 
            return "ef_proxy_interceptorFor" + memberName;
        } 
 
    }
 
    internal class BaseProxyImplementor
    {
        private readonly List _baseGetters;
        private readonly List _baseSetters; 

        public BaseProxyImplementor() 
        { 
            _baseGetters = new List();
            _baseSetters = new List(); 
        }

        public List BaseGetters
        { 
            get { return _baseGetters; }
        } 
 
        public List BaseSetters
        { 
            get { return _baseSetters; }
        }
        public void AddBasePropertyGetter(PropertyInfo baseProperty)
        { 
            _baseGetters.Add(baseProperty);
        } 
 
        public void AddBasePropertySetter(PropertyInfo baseProperty)
        { 
            _baseSetters.Add(baseProperty);
        }

        public void Implement(TypeBuilder typeBuilder, Action registerField) 
        {
            if (_baseGetters.Count > 0) 
            { 
                ImplementBaseGetter(typeBuilder);
            } 
            if (_baseSetters.Count > 0)
            {
                ImplementBaseSetter(typeBuilder);
            } 
        }
 
        static readonly MethodInfo s_StringEquals = typeof(string).GetMethod("op_Equality", new Type[] { typeof(string), typeof(string) }); 
        static readonly ConstructorInfo s_InvalidOperationConstructor = typeof(InvalidOperationException).GetConstructor(Type.EmptyTypes);
 
        private void ImplementBaseGetter(TypeBuilder typeBuilder)
        {
            // Define a property getter in the proxy type
            MethodBuilder getterBuilder = typeBuilder.DefineMethod("GetBasePropertyValue", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(object), new Type[] { typeof(string) }); 
            ILGenerator gen = getterBuilder.GetILGenerator();
            Label[] labels = new Label[_baseGetters.Count]; 
 
            for (int i = 0; i < _baseGetters.Count; i++)
            { 
                labels[i] = gen.DefineLabel();
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(OpCodes.Ldstr, _baseGetters[i].Name);
                gen.Emit(OpCodes.Call, s_StringEquals); 
                gen.Emit(OpCodes.Brfalse_S, labels[i]);
                gen.Emit(OpCodes.Ldarg_0); 
                gen.Emit(OpCodes.Call, _baseGetters[i].GetGetMethod(true)); 
                gen.Emit(OpCodes.Ret);
                gen.MarkLabel(labels[i]); 
            }
            gen.Emit(OpCodes.Newobj, s_InvalidOperationConstructor);
            gen.Emit(OpCodes.Throw);
        } 

        private void ImplementBaseSetter(TypeBuilder typeBuilder) 
        { 
            MethodBuilder setterBuilder = typeBuilder.DefineMethod("SetBasePropertyValue", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(string), typeof(object) });
            ILGenerator gen = setterBuilder.GetILGenerator(); 

            Label[] labels = new Label[_baseSetters.Count];

            for (int i = 0; i < _baseSetters.Count; i++) 
            {
                labels[i] = gen.DefineLabel(); 
                gen.Emit(OpCodes.Ldarg_1); 
                gen.Emit(OpCodes.Ldstr, _baseSetters[i].Name);
                gen.Emit(OpCodes.Call, s_StringEquals); 
                gen.Emit(OpCodes.Brfalse_S, labels[i]);
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldarg_2);
                gen.Emit(OpCodes.Castclass, _baseSetters[i].PropertyType); 
                gen.Emit(OpCodes.Call, _baseSetters[i].GetSetMethod(true));
                gen.Emit(OpCodes.Ret); 
                gen.MarkLabel(labels[i]); 
            }
            gen.Emit(OpCodes.Newobj, s_InvalidOperationConstructor); 
            gen.Emit(OpCodes.Throw);
        }
    }
 
    internal class IPOCOImplementor
    { 
        private EntityType _ospaceEntityType; 

        FieldBuilder _changeTrackerField; 
        FieldBuilder _relationshipManagerField;
        FieldBuilder _resetFKSetterFlagField;
        FieldBuilder _compareByteArraysField;
 
        MethodBuilder _entityMemberChanging;
        MethodBuilder _entityMemberChanged; 
        MethodBuilder _getRelationshipManager; 

        private List> _referenceProperties; 
        private List> _collectionProperties;
        private bool _implementIEntityWithChangeTracker;
        private bool _implementIEntityWithRelationships;
        private HashSet _scalarMembers; 
        private HashSet _relationshipMembers;
 
        static readonly MethodInfo s_EntityMemberChanging = typeof(IEntityChangeTracker).GetMethod("EntityMemberChanging", new Type[] { typeof(string) }); 
        static readonly MethodInfo s_EntityMemberChanged = typeof(IEntityChangeTracker).GetMethod("EntityMemberChanged", new Type[] { typeof(string) });
        static readonly MethodInfo s_CreateRelationshipManager = typeof(RelationshipManager).GetMethod("Create", new Type[] { typeof(IEntityWithRelationships) }); 
        static readonly MethodInfo s_GetRelationshipManager = typeof(IEntityWithRelationships).GetProperty("RelationshipManager").GetGetMethod();
        static readonly MethodInfo s_GetRelatedReference = typeof(RelationshipManager).GetMethod("GetRelatedReference", new Type[] { typeof(string), typeof(string) });
        static readonly MethodInfo s_GetRelatedCollection = typeof(RelationshipManager).GetMethod("GetRelatedCollection", new Type[] { typeof(string), typeof(string) });
        static readonly MethodInfo s_GetRelatedEnd = typeof(RelationshipManager).GetMethod("GetRelatedEnd", new Type[] { typeof(string), typeof(string) }); 
        static readonly MethodInfo s_ObjectEquals = typeof(object).GetMethod("Equals", new Type[] { typeof(object), typeof(object) });
        static readonly ConstructorInfo s_InvalidOperationConstructor = typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }); 
        static readonly MethodInfo s_IEntityWrapper_GetEntity = typeof(IEntityWrapper).GetProperty("Entity").GetGetMethod(); 
        static readonly MethodInfo s_Action_Invoke = typeof(Action).GetMethod("Invoke", new Type[] { typeof(object) });
        static readonly MethodInfo s_Func_object_object_bool_Invoke = typeof(Func).GetMethod("Invoke", new Type[] { typeof(object), typeof(object) }); 

        private static readonly ConstructorInfo s_BrowsableAttributeConstructor = typeof(BrowsableAttribute).GetConstructor(new Type[] { typeof(bool) });

        public IPOCOImplementor(EntityType ospaceEntityType) 
        {
            Type baseType = ospaceEntityType.ClrType; 
            _referenceProperties = new List>(); 
            _collectionProperties = new List>();
 
            _implementIEntityWithChangeTracker = (null == baseType.GetInterface(typeof(IEntityWithChangeTracker).Name));
            _implementIEntityWithRelationships = (null == baseType.GetInterface(typeof(IEntityWithRelationships).Name));

            CheckType(ospaceEntityType); 

            _ospaceEntityType = ospaceEntityType; 
        } 

        private void CheckType(EntityType ospaceEntityType) 
        {
            _scalarMembers = new HashSet();
            _relationshipMembers = new HashSet();
 
            foreach (EdmMember member in ospaceEntityType.Members)
            { 
                PropertyInfo clrProperty = EntityUtil.GetTopProperty(ospaceEntityType.ClrType, member.Name); 
                if (clrProperty != null && EntityProxyFactory.CanProxySetter(clrProperty))
                { 
                    if (member.BuiltInTypeKind == BuiltInTypeKind.EdmProperty)
                    {
                        if (_implementIEntityWithChangeTracker)
                        { 
                            _scalarMembers.Add(member);
                        } 
                    } 
                    else if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty)
                    { 
                        if (_implementIEntityWithRelationships)
                        {
                            NavigationProperty navProperty = (NavigationProperty)member;
                            RelationshipMultiplicity multiplicity = navProperty.ToEndMember.RelationshipMultiplicity; 

                            if (multiplicity == RelationshipMultiplicity.Many) 
                            { 
                                if (clrProperty.PropertyType.IsGenericType &&
                                    clrProperty.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)) 
                                {
                                    _relationshipMembers.Add(member);
                                }
                            } 
                            else
                            { 
                                _relationshipMembers.Add(member); 
                            }
                        } 
                    }
                }
            }
 
            if (ospaceEntityType.Members.Count != _scalarMembers.Count + _relationshipMembers.Count)
            { 
                _scalarMembers.Clear(); 
                _relationshipMembers.Clear();
                _implementIEntityWithChangeTracker = false; 
                _implementIEntityWithRelationships = false;
            }
        }
 
        public void Implement(TypeBuilder typeBuilder, Action registerField)
        { 
            if (_implementIEntityWithChangeTracker) 
            {
                ImplementIEntityWithChangeTracker(typeBuilder, registerField); 
            }
            if (_implementIEntityWithRelationships)
            {
                ImplementIEntityWithRelationships(typeBuilder, registerField); 
            }
 
            _resetFKSetterFlagField = typeBuilder.DefineField(EntityProxyFactory.ResetFKSetterFlagFieldName, typeof(Action), FieldAttributes.Private| FieldAttributes.Static); 
            _compareByteArraysField = typeBuilder.DefineField(EntityProxyFactory.CompareByteArraysFieldName, typeof(Func), FieldAttributes.Private | FieldAttributes.Static);
        } 

        public Type[] Interfaces
        {
            get 
            {
                List types = new List(); 
                if (_implementIEntityWithChangeTracker) { types.Add(typeof(IEntityWithChangeTracker)); } 
                if (_implementIEntityWithRelationships) { types.Add(typeof(IEntityWithRelationships)); }
                return types.ToArray(); 
            }
        }

        public DynamicMethod CreateInitalizeCollectionMethod(Type proxyType) 
        {
            if (_collectionProperties.Count > 0) 
            { 
                DynamicMethod initializeEntityCollections = LightweightCodeGenerator.CreateDynamicMethod(proxyType.Name + "_InitializeEntityCollections", typeof(IEntityWrapper), new Type[] { typeof(IEntityWrapper) });
                ILGenerator generator = initializeEntityCollections.GetILGenerator(); 
                generator.DeclareLocal(proxyType);
                generator.DeclareLocal(typeof(RelationshipManager));
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Callvirt, s_IEntityWrapper_GetEntity); 
                generator.Emit(OpCodes.Castclass, proxyType);
                generator.Emit(OpCodes.Stloc_0); 
                generator.Emit(OpCodes.Ldloc_0); 
                generator.Emit(OpCodes.Callvirt, s_GetRelationshipManager);
                generator.Emit(OpCodes.Stloc_1); 

                foreach (KeyValuePair navProperty in _collectionProperties)
                {
                    // Update Constructor to initialize this property 
                    MethodInfo getRelatedCollection = s_GetRelatedCollection.MakeGenericMethod(EntityUtil.GetCollectionElementType(navProperty.Value.PropertyType));
 
                    generator.Emit(OpCodes.Ldloc_0); 
                    generator.Emit(OpCodes.Ldloc_1);
                    generator.Emit(OpCodes.Ldstr, navProperty.Key.RelationshipType.FullName); 
                    generator.Emit(OpCodes.Ldstr, navProperty.Key.ToEndMember.Name);
                    generator.Emit(OpCodes.Callvirt, getRelatedCollection);
                    generator.Emit(OpCodes.Callvirt, navProperty.Value.GetSetMethod(true));
                } 
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ret); 
 
                return initializeEntityCollections;
            } 
            return null;
        }

        public bool CanProxyMember(EdmMember member) 
        {
            return _scalarMembers.Contains(member) || _relationshipMembers.Contains(member); 
        } 

        public bool EmitMember(TypeBuilder typeBuilder, EdmMember member, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, BaseProxyImplementor baseImplementor) 
        {
            if (_scalarMembers.Contains(member))
            {
                bool isKeyMember = _ospaceEntityType.KeyMembers.Contains(member.Identity); 
                EmitScalarSetter(typeBuilder, propertyBuilder, baseProperty, isKeyMember);
                return true; 
            } 
            else if (_relationshipMembers.Contains(member))
            { 
                Debug.Assert(member != null, "member is null");
                Debug.Assert(member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty);
                NavigationProperty navProperty = member as NavigationProperty;
                if (navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) 
                {
                    EmitCollectionProperty(typeBuilder, propertyBuilder, baseProperty, navProperty); 
                } 
                else
                { 
                    EmitReferenceProperty(typeBuilder, propertyBuilder, baseProperty, navProperty);
                }
                baseImplementor.AddBasePropertySetter(baseProperty);
                return true; 
            }
            return false; 
        } 

        private void EmitScalarSetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, bool isKeyMember) 
        {
            MethodInfo baseSetter = baseProperty.GetSetMethod(true);
            const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
            MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask; 

            MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType }); 
            ILGenerator generator = setterBuilder.GetILGenerator(); 
            Label endOfMethod = generator.DefineLabel();
 
            // If the CLR property represents a key member of the Entity Type,
            // ignore attempts to set the key value to the same value.
            if (isKeyMember)
            { 
                MethodInfo baseGetter = baseProperty.GetGetMethod(true);
 
                if (baseGetter != null) 
                {
                    // if (base.[Property] != value) 
                    // {
                    //     // perform set operation
                    // }
 
                    Type propertyType = baseProperty.PropertyType;
 
                    if (propertyType == typeof(int) ||         // signed integer types 
                        propertyType == typeof(short) ||
                        propertyType == typeof(Int64) || 
                        propertyType == typeof(bool) ||        // boolean
                        propertyType == typeof(byte) ||
                        propertyType == typeof(UInt32) ||
                        propertyType == typeof(UInt64)|| 
                        propertyType == typeof(float) ||
                        propertyType == typeof(decimal)) 
                    { 
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Call, baseGetter); 
                        generator.Emit(OpCodes.Ldarg_1);
                        generator.Emit(OpCodes.Beq_S, endOfMethod);
                    }
                    else if (propertyType == typeof(byte[])) 
                    {
                        // Byte arrays must be compared by value 
                        generator.Emit(OpCodes.Ldsfld, _compareByteArraysField); 
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Call, baseGetter); 
                        generator.Emit(OpCodes.Ldarg_1);
                        generator.Emit(OpCodes.Callvirt, s_Func_object_object_bool_Invoke);
                        generator.Emit(OpCodes.Brtrue_S, endOfMethod);
                    } 
                    else
                    { 
                        // Get the specific type's inequality method if it exists 
                        MethodInfo op_inequality = propertyType.GetMethod("op_Inequality", new Type[] { propertyType, propertyType });
                        if (op_inequality != null) 
                        {
                            generator.Emit(OpCodes.Ldarg_0);
                            generator.Emit(OpCodes.Call, baseGetter);
                            generator.Emit(OpCodes.Ldarg_1); 
                            generator.Emit(OpCodes.Call, op_inequality);
                            generator.Emit(OpCodes.Brfalse_S, endOfMethod); 
                        } 
                        else
                        { 
                            // Use object inequality
                            generator.Emit(OpCodes.Ldarg_0);
                            generator.Emit(OpCodes.Call, baseGetter);
                            if (propertyType.IsValueType) 
                            {
                                generator.Emit(OpCodes.Box, propertyType); 
                            } 
                            generator.Emit(OpCodes.Ldarg_1);
                            if (propertyType.IsValueType) 
                            {
                                generator.Emit(OpCodes.Box, propertyType);
                            }
                            generator.Emit(OpCodes.Call, s_ObjectEquals); 
                            generator.Emit(OpCodes.Brtrue_S, endOfMethod);
                        } 
                    } 
                }
            } 

            // Creates code like this:
            //
            // try 
            // {
            //     MemberChanging(propertyName); 
            //     base.Property_set(value); 
            //     MemberChanged(propertyName);
            // } 
            // finally
            // {
            //     _resetFKSetterFlagField(this);
            // } 
            //
            // Note that the try/finally ensures that even if an exception causes 
            // the setting of the property to be aborted, we still clear the flag that 
            // indicates that we are in a property setter.
 
            generator.BeginExceptionBlock();
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldstr, baseProperty.Name);
            generator.Emit(OpCodes.Call, _entityMemberChanging); 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldarg_1); 
            generator.Emit(OpCodes.Call, baseSetter); 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldstr, baseProperty.Name); 
            generator.Emit(OpCodes.Call, _entityMemberChanged);
            generator.BeginFinallyBlock();
            generator.Emit(OpCodes.Ldsfld, _resetFKSetterFlagField);
            generator.Emit(OpCodes.Ldarg_0); 
            generator.Emit(OpCodes.Callvirt, s_Action_Invoke);
            generator.EndExceptionBlock(); 
            generator.MarkLabel(endOfMethod); 
            generator.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setterBuilder); 
        }

        private void EmitReferenceProperty(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, NavigationProperty navProperty)
        { 
            const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
            MethodInfo baseSetter = baseProperty.GetSetMethod(true); ; 
            MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask; 

            MethodInfo specificGetRelatedReference = s_GetRelatedReference.MakeGenericMethod(baseProperty.PropertyType); 
            MethodInfo specificEntityReferenceSetValue = typeof(EntityReference<>).MakeGenericType(baseProperty.PropertyType).GetMethod("set_Value"); ;

            MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType });
            ILGenerator generator = setterBuilder.GetILGenerator(); 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Callvirt, _getRelationshipManager); 
            generator.Emit(OpCodes.Ldstr, navProperty.RelationshipType.FullName); 
            generator.Emit(OpCodes.Ldstr, navProperty.ToEndMember.Name);
            generator.Emit(OpCodes.Callvirt, specificGetRelatedReference); 
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Callvirt, specificEntityReferenceSetValue);
            generator.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setterBuilder); 

            _referenceProperties.Add(new KeyValuePair(navProperty, baseProperty)); 
        } 

        private void EmitCollectionProperty(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, NavigationProperty navProperty) 
        {
            const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
            MethodInfo baseSetter = baseProperty.GetSetMethod(true); ;
            MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask; 

            string cannotSetException = System.Data.Entity.Strings.EntityProxyTypeInfo_CannotSetEntityCollectionProperty(propertyBuilder.Name, typeBuilder.Name); 
            MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType }); 
            ILGenerator generator = setterBuilder.GetILGenerator();
            Label instanceEqual = generator.DefineLabel(); 
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Call, _getRelationshipManager);
            generator.Emit(OpCodes.Ldstr, navProperty.RelationshipType.FullName); 
            generator.Emit(OpCodes.Ldstr, navProperty.ToEndMember.Name);
            generator.Emit(OpCodes.Callvirt, s_GetRelatedEnd); 
            generator.Emit(OpCodes.Beq_S, instanceEqual); 
            generator.Emit(OpCodes.Ldstr, cannotSetException);
            generator.Emit(OpCodes.Newobj, s_InvalidOperationConstructor); 
            generator.Emit(OpCodes.Throw);
            generator.MarkLabel(instanceEqual);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldarg_1); 
            generator.Emit(OpCodes.Call, baseProperty.GetSetMethod(true));
            generator.Emit(OpCodes.Ret); 
            propertyBuilder.SetSetMethod(setterBuilder); 

            _collectionProperties.Add(new KeyValuePair(navProperty, baseProperty)); 
        }

        #region Interface Implementation
 
        private void ImplementIEntityWithChangeTracker(TypeBuilder typeBuilder, Action registerField)
        { 
            _changeTrackerField = typeBuilder.DefineField("_changeTracker", typeof(IEntityChangeTracker), FieldAttributes.Private); 
            registerField(_changeTrackerField, false);
 
            // Implement EntityMemberChanging(string propertyName)
            _entityMemberChanging = typeBuilder.DefineMethod("EntityMemberChanging", MethodAttributes.Private | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(string) });
            ILGenerator generator = _entityMemberChanging.GetILGenerator();
            Label methodEnd = generator.DefineLabel(); 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, _changeTrackerField); 
            generator.Emit(OpCodes.Brfalse_S, methodEnd); 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, _changeTrackerField); 
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Callvirt, s_EntityMemberChanging);
            generator.MarkLabel(methodEnd);
            generator.Emit(OpCodes.Ret); 

            // Implement EntityMemberChanged(string propertyName) 
            _entityMemberChanged = typeBuilder.DefineMethod("EntityMemberChanged", MethodAttributes.Private | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(string) }); 
            generator = _entityMemberChanged.GetILGenerator();
            methodEnd = generator.DefineLabel(); 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, _changeTrackerField);
            generator.Emit(OpCodes.Brfalse_S, methodEnd);
            generator.Emit(OpCodes.Ldarg_0); 
            generator.Emit(OpCodes.Ldfld, _changeTrackerField);
            generator.Emit(OpCodes.Ldarg_1); 
            generator.Emit(OpCodes.Callvirt, s_EntityMemberChanged); 
            generator.MarkLabel(methodEnd);
            generator.Emit(OpCodes.Ret); 

            // Implement IEntityWithChangeTracker.SetChangeTracker(IEntityChangeTracker changeTracker)
            MethodBuilder setChangeTracker = typeBuilder.DefineMethod("SetChangeTracker", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
                typeof(void), new Type[] { typeof(IEntityChangeTracker) }); 
            generator = setChangeTracker.GetILGenerator();
            generator.Emit(OpCodes.Ldarg_0); 
            generator.Emit(OpCodes.Ldarg_1); 
            generator.Emit(OpCodes.Stfld, _changeTrackerField);
            generator.Emit(OpCodes.Ret); 
        }

        private void ImplementIEntityWithRelationships(TypeBuilder typeBuilder, Action registerField)
        { 
            _relationshipManagerField = typeBuilder.DefineField("_relationshipManager", typeof(RelationshipManager), FieldAttributes.Private);
            registerField(_relationshipManagerField, true); 
 
            PropertyBuilder relationshipManagerProperty = typeBuilder.DefineProperty("RelationshipManager", System.Reflection.PropertyAttributes.None, typeof(RelationshipManager), Type.EmptyTypes);
 
            // Implement IEntityWithRelationships.get_RelationshipManager
            _getRelationshipManager = typeBuilder.DefineMethod("get_RelationshipManager", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final,
                typeof(RelationshipManager), Type.EmptyTypes);
            ILGenerator generator = _getRelationshipManager.GetILGenerator(); 
            Label trueLabel = generator.DefineLabel();
            generator.Emit(OpCodes.Ldarg_0); 
            generator.Emit(OpCodes.Ldfld, _relationshipManagerField); 
            generator.Emit(OpCodes.Brtrue_S, trueLabel);
            generator.Emit(OpCodes.Ldarg_0); 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Call, s_CreateRelationshipManager);
            generator.Emit(OpCodes.Stfld, _relationshipManagerField);
            generator.MarkLabel(trueLabel); 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, _relationshipManagerField); 
            generator.Emit(OpCodes.Ret); 
            relationshipManagerProperty.SetGetMethod(_getRelationshipManager);
        } 

        #endregion
    }
 
    /// 
    /// Add a DataContractAttribute to the proxy type, based on one that may have been applied to the base type. 
    ///  
    /// 
    ///  
    /// From http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx:
    ///
    /// A data contract has two basic requirements: a stable name and a list of members.
    /// The stable name consists of the namespace uniform resource identifier (URI) and the local name of the contract. 
    /// By default, when you apply the DataContractAttribute to a class,
    /// it uses the class name as the local name and the class's namespace (prefixed with "http://schemas.datacontract.org/2004/07/") 
    /// as the namespace URI. You can override the defaults by setting the Name and Namespace properties. 
    /// You can also change the namespace by applying the ContractNamespaceAttribute to the namespace.
    /// Use this capability when you have an existing type that processes data exactly as you require 
    /// but has a different namespace and class name from the data contract.
    /// By overriding the default values, you can reuse your existing type and have the serialized data conform to the data contract.
    /// 
    ///  
    /// The first attempt at WCF serialization of proxies involved adding a DataContractAttribute to the proxy type in such a way
    /// so that the name and namespace of the proxy's data contract matched that of the base class. 
    /// This worked when serializing proxy objects for the root type of the DataContractSerializer, 
    /// but not for proxy objects of types derived from the root type.
    /// 
    /// Attempting to add the proxy type to the list of known types failed as well,
    /// since the data contract of the proxy type did not match the base type as intended.
    /// This was due to the fact that inheritance is captured in the data contract.
    /// So while the proxy and base data contracts had the same members, the proxy data contract differed in that is declared itself 
    /// as an extension of the base data contract.  So the data contracts were technically not equivalent.
    /// 
    /// The approach used instead is to allow proxy types to have their own DataContract. 
    /// Users then have at least two options available to them.
    /// 
    /// The first approach is to add the proxy types to the list of known types.
    ///
    /// The second approach is to implement an IDataContractSurrogate that can map a proxy instance to a surrogate that does have a data contract
    /// equivalent to the base type (you could use the base type itself for this purpose). 
    /// While more complex to implement, it allows services to hide the use of proxies from clients.
    /// This can be quite useful in order to maximize potential interoperability. 
    ///  
    /// 
    internal sealed class DataContractImplementor 
    {
        private static readonly ConstructorInfo s_DataContractAttributeConstructor = typeof(DataContractAttribute).GetConstructor(Type.EmptyTypes);
        private static readonly PropertyInfo[] s_DataContractProperties = new PropertyInfo[] {
            typeof(DataContractAttribute).GetProperty("IsReference") 
        };
 
        private readonly Type _baseClrType; 
        private readonly DataContractAttribute _dataContract;
 
        internal DataContractImplementor(EntityType ospaceEntityType)
        {
            _baseClrType = ospaceEntityType.ClrType;
 
            DataContractAttribute[] attributes = (DataContractAttribute[])_baseClrType.GetCustomAttributes(typeof(DataContractAttribute), false);
            if (attributes.Length > 0) 
            { 
                _dataContract = attributes[0];
            } 
        }

        internal void Implement(TypeBuilder typeBuilder, Action registerField)
        { 
            if (_dataContract != null)
            { 
                // Use base data contract properties to help determine values of properties the proxy type's data contract. 
                object[] propertyValues = new object[] {
                    // IsReference 
                    _dataContract.IsReference
                };

                CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(s_DataContractAttributeConstructor, new object[0], s_DataContractProperties, propertyValues); 
                typeBuilder.SetCustomAttribute(attributeBuilder);
            } 
        } 
    }
 
    /// 
    /// This class determines if the proxied type implements ISerializable with the special serialization constructor.
    /// If it does, it adds the appropriate members to the proxy type.
    ///  
    internal sealed class ISerializableImplementor
    { 
        private readonly Type _baseClrType; 
        private readonly bool _baseImplementsISerializable;
        private readonly bool _canOverride; 
        private readonly MethodInfo _getObjectDataMethod;
        private readonly ConstructorInfo _serializationConstructor;

        internal ISerializableImplementor(EntityType ospaceEntityType) 
        {
            _baseClrType = ospaceEntityType.ClrType; 
            _baseImplementsISerializable = _baseClrType.IsSerializable && typeof(ISerializable).IsAssignableFrom(_baseClrType); 

            if (_baseImplementsISerializable) 
            {
                // Determine if interface implementation can be overridden.
                // Fortunately, there's only one method to check.
                InterfaceMapping mapping = _baseClrType.GetInterfaceMap(typeof(ISerializable)); 
                _getObjectDataMethod = mapping.TargetMethods[0];
 
                // Members that implement interfaces must be public, unless they are explicitly implemented, in which case they are private and sealed (at least for C#). 
                bool canOverrideMethod = (_getObjectDataMethod.IsVirtual && !_getObjectDataMethod.IsFinal) && _getObjectDataMethod.IsPublic;
 
                if (canOverrideMethod)
                {
                    // Determine if proxied type provides the special serialization constructor.
                    // In order for the proxy class to properly support ISerializable, this constructor must not be private. 
                    _serializationConstructor = _baseClrType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }, null);
 
                    _canOverride = _serializationConstructor != null && (_serializationConstructor.IsPublic || _serializationConstructor.IsFamily || _serializationConstructor.IsFamilyOrAssembly); 
                }
 
                Debug.Assert(!(_canOverride && (_getObjectDataMethod == null || _serializationConstructor == null)), "Both GetObjectData method and Serialization Constructor must be present when proxy overrides ISerializable implementation.");
            }
        }
 
        internal bool TypeIsSuitable
        { 
            get 
            {
                // To be suitable, 
                // either proxied type doesn't implement ISerializable,
                // or it does and it can be suitably overridden.
                return !_baseImplementsISerializable || _canOverride;
            } 
        }
 
        internal bool TypeImplementsISerializable 
        {
            get 
            {
                return _baseImplementsISerializable;
            }
        } 

        internal void Implement(TypeBuilder typeBuilder, IEnumerable serializedFields) 
        { 
            if (_baseImplementsISerializable && _canOverride)
            { 
                PermissionSet serializationFormatterPermissions = new PermissionSet(null);
                serializationFormatterPermissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));

                Type[] parameterTypes = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }; 
                MethodInfo getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) });
                MethodInfo addValue = typeof(SerializationInfo).GetMethod("AddValue", new Type[] { typeof(string), typeof(object), typeof(Type) }); 
                MethodInfo getValue = typeof(SerializationInfo).GetMethod("GetValue", new Type[] { typeof(string), typeof(Type) }); 

                // 
                // Define GetObjectData method override
                //
                // [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
                // public void GetObjectData(SerializationInfo info, StreamingContext context) 
                //
                MethodBuilder proxyGetObjectData = typeBuilder.DefineMethod(_getObjectDataMethod.Name, 
                                                                            MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, 
                                                                            null,
                                                                            parameterTypes); 
                proxyGetObjectData.AddDeclarativeSecurity(SecurityAction.Demand, serializationFormatterPermissions);

                {
                    ILGenerator generator = proxyGetObjectData.GetILGenerator(); 

                    // Call SerializationInfo.AddValue to serialize each field value 
                    foreach (FieldBuilder field in serializedFields) 
                    {
                        generator.Emit(OpCodes.Ldarg_1); 
                        generator.Emit(OpCodes.Ldstr, field.Name);
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Ldfld, field);
                        generator.Emit(OpCodes.Ldtoken, field.FieldType); 
                        generator.Emit(OpCodes.Call, getTypeFromHandle);
                        generator.Emit(OpCodes.Callvirt, addValue); 
                    } 

                    // Emit call to base method 
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldarg_1);
                    generator.Emit(OpCodes.Ldarg_2);
                    generator.Emit(OpCodes.Call, _getObjectDataMethod); 
                    generator.Emit(OpCodes.Ret);
                } 
 
                //
                // Define serialization constructor 
                //
                // [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
                // .ctor(SerializationInfo info, StreamingContext context)
                // 
                MethodAttributes constructorAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
                constructorAttributes |= _serializationConstructor.IsPublic? MethodAttributes.Public : MethodAttributes.Private; 
 
                ConstructorBuilder proxyConstructor = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard | CallingConventions.HasThis, parameterTypes);
                proxyConstructor.AddDeclarativeSecurity(SecurityAction.Demand, serializationFormatterPermissions); 

                {
                    //Emit call to base serialization constructor
                    ILGenerator generator = proxyConstructor.GetILGenerator(); 
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldarg_1); 
                    generator.Emit(OpCodes.Ldarg_2); 
                    generator.Emit(OpCodes.Call, _serializationConstructor);
 
                    // Call SerializationInfo.GetValue to retrieve the value of each field
                    foreach (FieldBuilder field in serializedFields)
                    {
                        generator.Emit(OpCodes.Ldarg_0); 
                        generator.Emit(OpCodes.Ldarg_1);
                        generator.Emit(OpCodes.Ldstr, field.Name); 
                        generator.Emit(OpCodes.Ldtoken, field.FieldType); 
                        generator.Emit(OpCodes.Call, getTypeFromHandle);
                        generator.Emit(OpCodes.Callvirt, getValue); 
                        generator.Emit(OpCodes.Castclass, field.FieldType);
                        generator.Emit(OpCodes.Stfld, field);
                    }
 
                    generator.Emit(OpCodes.Ret);
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK