LightweightCodeGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Metadata / Edm / LightweightCodeGenerator.cs / 1 / LightweightCodeGenerator.cs

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

namespace System.Data.Objects 
{
    using System;
    using System.Data.Metadata.Edm;
    using System.Diagnostics; 
    using System.Reflection;
    using System.Reflection.Emit; 
    using System.Security; 
    using System.Security.Permissions;
    using System.Data.Objects.DataClasses; 
    using System.Data.Common.Utils;
    using System.Linq;

    ///  
    /// CodeGenerator class: use lightweight code gen to dynamically generate code to get/set properties.
    ///  
    internal static class LightweightCodeGenerator 
    {
 
        /// For an OSpace ComplexType or EntityType, returns the delegate to construct the clr instance.
        internal static Delegate GetConstructorDelegateForType(EdmType clrType)
        {
            return (Helper.IsEntityType(clrType) 
                    ? GetConstructorDelegateForType((ClrEntityType)clrType)
                    : GetConstructorDelegateForType((ClrComplexType)clrType)); 
        } 

        /// For an OSpace ComplexType or EntityType, returns the delegate to construct the clr instance. 
        internal static Delegate GetConstructorDelegateForType(ClrEntityType clrType)
        {
            return (clrType.Constructor ?? (clrType.Constructor = CreateEntityConstructor(clrType.ClrType)));
        } 

        internal static Delegate GetConstructorDelegateForType(ClrComplexType clrType) 
        { 
            return (clrType.Constructor ?? (clrType.Constructor = CreateConstructor(clrType.ClrType)));
        } 

        /// for an OSpace property, get the property value from a clr instance
        internal static object GetValue(NavigationProperty property, object target)
        { 
            Func getter = property.ValueGetter;
            if (null == getter) 
            { 
                getter = CreatePropertyGetter(property.PropertyGetterHandle);
                property.ValueGetter = getter; 
            }
            Debug.Assert(null != getter, "null getter");

            //Not tracing every property get 
            //EntityBid.Trace(" Name='%ls'\n", property.Name);
            return getter(target); 
        } 

        /// for an OSpace property, get the property value from a clr instance 
        internal static object GetValue(EdmProperty property, object target)
        {
            Func getter = GetGetterDelegateForProperty(property);
            Debug.Assert(null != getter, "null getter"); 

            //Not tracing every property get 
            //EntityBid.Trace(" Name='%ls'\n", property.Name); 
            return getter(target);
        } 

        internal static Func GetGetterDelegateForProperty(EdmProperty property)
        {
            return property.ValueGetter ?? (property.ValueGetter = CreatePropertyGetter(property.PropertyGetterHandle)); 
        }
 
        /// for an OSpace property, set the property value on a clr instance 
        /// 
        /// If  is null for a non nullable property. 
        /// 
        /// 
        /// Invalid cast of  to property type.
        ///  
        /// 
        /// From generated enties via StructuralObject.SetValidValue. 
        ///  
        /// 
        /// If the property setter is not public or declaring class is not public. 
        /// 
        /// 
        /// Demand for FullTrust if the property setter or declaring class has a 
        ///  
        internal static void SetValue(EdmProperty property, object target, object value)
        { 
            Action setter = GetSetterDelegateForProperty(property); 
            if (Bid.TraceOn)
            { 
                EntityBid.Trace(" Name='%ls'\n", property.Name);
            }
            setter(target, value);
        } 

        /// For an OSpace property, gets the delegate to set the property value on a clr instance. 
        internal static Action GetSetterDelegateForProperty(EdmProperty property) 
        {
            Action setter = property.ValueSetter; 
            if (null == setter)
            {
                setter = CreatePropertySetter(property.PropertySetterHandle,
                        property.Nullable); 
                property.ValueSetter = setter;
            } 
            Debug.Assert(null != setter, "null setter"); 
            return setter;
        } 

        /// 
        /// Gets the related end instance for the source AssociationEndMember by creating a DynamicMethod to
        /// call GetRelatedCollection or GetRelatedReference 
        /// 
        internal static IRelatedEnd GetRelatedEnd(RelationshipManager sourceRelationshipManager, AssociationEndMember sourceMember, AssociationEndMember targetMember, RelatedEnd existingRelatedEnd) 
        { 
            RelationshipManager.GetRelatedEndMethod getRelatedEnd = sourceMember.GetRelatedEnd as RelationshipManager.GetRelatedEndMethod;
            if (null == getRelatedEnd) 
            {
                getRelatedEnd = CreateGetRelatedEndMethod(sourceMember, targetMember, existingRelatedEnd);
                sourceMember.GetRelatedEnd = getRelatedEnd;
            } 
            Debug.Assert(null != getRelatedEnd, "null getRelatedEnd");
 
            //Not tracing every property get 
            //EntityBid.Trace(" Name='%ls'\n", property.Name);
            return getRelatedEnd(sourceRelationshipManager, existingRelatedEnd); 
        }

        #region get the delegate
 
        /// Gets a parameterless constructor for the specified type.
        /// Type to get constructor for. 
        /// Parameterless constructor for the specified type. 
        internal static ConstructorInfo GetConstructorForType(Type type)
        { 
            System.Diagnostics.Debug.Assert(type != null);
            ConstructorInfo ci = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, System.Type.EmptyTypes, null);
            if (null == ci)
            { 
                ThrowConstructorNoParameterless();
            } 
            return ci; 
        }
 

        /// 
        /// generate a delegate equivalent to
        /// private object Constructor() { return new XClass(); } 
        /// 
        private static Delegate CreateConstructor(Type type) 
        { 
            ConstructorInfo ci = GetConstructorForType(type);
 
            // because CreateDynamicMethod asserts ReflectionPermission, method is "elevated" and must be treated carefully
            DynamicMethod method = CreateDynamicMethod(ci.DeclaringType.Name, typeof(object), Type.EmptyTypes);
            ILGenerator gen = method.GetILGenerator();
            GenerateNecessaryPermissionDemands(gen, ci); 

            gen.Emit(OpCodes.Newobj, ci); 
            gen.Emit(OpCodes.Ret); 
            return method.CreateDelegate(typeof(Func));
        } 

        /// 
        /// generate a delegate equivalent to
        /// private object Constructor(EntityKey, ObjectContext, EntitySet, MergeOption) { 
        ///    object value = new XClass();
        /// 
        ///    if (null != entityKey) { 
        ///      #if XClass implements IEntityKey
        ///      ((IEntityWithKey)this).EntityKey = entityKey; 
        ///      #endif
        ///
        ///      #if XClass implements IEntityWithRelationships
        ///      RelationshipManager manager = ((IEntityWithRelationships)this).RelationshipManager; 
        ///      if (null != manager) { manager.AttachContext(ObjectContext, EntitySet, MergeOption); }
        ///    } 
        /// 
        ///    return value;
        /// return new XClass(); } 
        /// 
        private static Delegate CreateEntityConstructor(Type type)
        {
            ConstructorInfo ci = GetConstructorForType(type); 

            // because CreateDynamicMethod asserts ReflectionPermission, method is "elevated" and must be treated carefully 
            DynamicMethod method = CreateDynamicMethod(ci.DeclaringType.Name, typeof(object), new Type[] { typeof(EntityKey), typeof(ObjectContext), typeof(EntitySet), typeof(MergeOption) }); 
            ILGenerator gen = method.GetILGenerator();
            GenerateNecessaryPermissionDemands(gen, ci); 

            gen.Emit(OpCodes.Newobj, ci);

            bool withKey = typeof(IEntityWithKey).IsAssignableFrom(type); 
            bool withRel = typeof(IEntityWithRelationships).IsAssignableFrom(type);
 
            if (withKey || withRel) 
            {
                Label nullEntityKey = gen.DefineLabel(); 
                gen.Emit(OpCodes.Ldarg_0);                  // EntityKey
                gen.Emit(OpCodes.Brfalse_S, nullEntityKey); // null EntityKey

                if (withKey) 
                {
                    gen.Emit(OpCodes.Dup);                      // the Newobj 
                    gen.Emit(OpCodes.Castclass, typeof(IEntityWithKey)); 
                    gen.Emit(OpCodes.Ldarg_0);                  // EntityKey
                    gen.Emit(OpCodes.Callvirt, typeof(IEntityWithKey).GetMethod("set_EntityKey", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(EntityKey) }, null)); 
                }

                // The only reason we would call RelationshipManager.AttachContext would be to enable loading related entities,
                // but if there’s no entitykey (aka NoEntitySetKey), then there’s no way that should work. 
                // So it’s reasonable not to call RelationshipManager.AttachContext unless there is a valid EntityKey
                if (withRel) 
                { 
                    Label nullContext = gen.DefineLabel();
 
                    gen.Emit(OpCodes.Ldarg_1);                  // ObjectContext
                    gen.Emit(OpCodes.Brfalse_S, nullContext);   // null context, don't AttachContext

                    gen.Emit(OpCodes.Dup);                      // the Newobj 
                    gen.Emit(OpCodes.Castclass, typeof(IEntityWithRelationships));
                    gen.Emit(OpCodes.Ldarg_1);                  // ObjectContext 
                    gen.Emit(OpCodes.Ldarg_2);                  // EntitySet 
                    gen.Emit(OpCodes.Ldarg_3);                  // MergeOption
 
                    Debug.Assert(null != (Action)EntityUtil.AttachContext, "missing method AttachContext(IEntityWithRelationships, ObjectContext, EntitySet, MergeOption)");
                    gen.Emit(OpCodes.Call, typeof(EntityUtil).GetMethod("AttachContext", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(IEntityWithRelationships), typeof(ObjectContext), typeof(EntitySet), typeof(MergeOption) }, null));

                    gen.MarkLabel(nullContext); 
                }
                gen.MarkLabel(nullEntityKey); 
            } 

            gen.Emit(OpCodes.Ret); 
            return method.CreateDelegate(typeof(Func));
        }

        ///  
        /// generate a delegate equivalent to
        /// private object MemberGetter(object target) { return target.PropertyX; } 
        /// or if the property is Nullable<> generate a delegate equivalent to 
        /// private object MemberGetter(object target) { Nullable y = target.PropertyX; return ((y.HasValue) ? y.Value : null); }
        ///  
        private static Func CreatePropertyGetter(RuntimeMethodHandle rmh)
        {
            MethodInfo mi = ((IntPtr.Zero != rmh.Value) ? (MethodInfo)MethodBase.GetMethodFromHandle(rmh) : null);
            if (null == mi) 
            {
                ThrowPropertyNoGetter(); 
            } 
            if (mi.IsStatic)
            { 
                ThrowPropertyIsStatic();
            }
            if (mi.DeclaringType.IsValueType)
            { 
                ThrowPropertyDeclaringTypeIsValueType();
            } 
 
            if (0 != mi.GetParameters().Length)
            { 
                ThrowPropertyIsIndexed();
            }

            Type realType = mi.ReturnType; 
            if ((null == realType) || (typeof(void) == realType))
            { 
                ThrowPropertyUnsupportedForm(); 
            }
            if (realType.IsPointer) 
            {
                ThrowPropertyUnsupportedType();
            }
 
            // because CreateDynamicMethod asserts ReflectionPermission, method is "elevated" and must be treated carefully
            DynamicMethod method = CreateDynamicMethod(mi.Name, typeof(object), new Type[] { typeof(object) }); 
            ILGenerator gen = method.GetILGenerator(); 
            GenerateNecessaryPermissionDemands(gen, mi);
 
            // the 'this' target pointer
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, mi.DeclaringType);
            gen.Emit(mi.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, mi); 

            if (realType.IsValueType) 
            { 
                Type elementType;
                if (realType.IsGenericType && (typeof(Nullable<>) == realType.GetGenericTypeDefinition())) 
                {
                    elementType = realType.GetGenericArguments()[0];

                    Label lableFalse = gen.DefineLabel(); 
                    LocalBuilder local = gen.DeclareLocal(realType);
                    gen.Emit(OpCodes.Stloc_S, local); 
 
                    gen.Emit(OpCodes.Ldloca_S, local);
                    gen.Emit(OpCodes.Call, realType.GetMethod("get_HasValue")); 
                    gen.Emit(OpCodes.Brfalse_S, lableFalse);

                    gen.Emit(OpCodes.Ldloca_S, local);
                    gen.Emit(OpCodes.Call, realType.GetMethod("get_Value")); 
                    gen.Emit(OpCodes.Box, elementType = realType.GetGenericArguments()[0]);
                    gen.Emit(OpCodes.Ret); 
 
                    gen.MarkLabel(lableFalse);
                    gen.Emit(OpCodes.Ldnull); 
                }
                else
                {
                    // need to box to return value as object 
                    elementType = realType;
                    gen.Emit(OpCodes.Box, elementType); 
                } 
            }
            gen.Emit(OpCodes.Ret); 
            return (Func)method.CreateDelegate(typeof(Func));
        }

        ///  
        /// generate a delegate equivalent to
        /// 
        /// // if Property is Nullable value type 
        /// private void MemberSetter(object target, object value) {
        ///     if (AllwNull && (null == value)) { 
        ///         ((TargetType)target).PropertyName = default(PropertyType?);
        ///         return;
        ///     }
        ///     if (value is PropertyType) { 
        ///             ((TargetType)target).PropertyName = new (PropertyType?)((PropertyType)value);
        ///         return; 
        ///     } 
        ///     ThrowInvalidValue(value, TargetType.Name, PropertyName);
        ///     return 
        /// }
        ///
        /// // when PropertyType is a value type
        /// private void MemberSetter(object target, object value) { 
        ///     if (value is PropertyType) {
        ///             ((TargetType)target).PropertyName = (PropertyType)value; 
        ///         return; 
        ///     }
        ///     ThrowInvalidValue(value, TargetType.Name, PropertyName); 
        ///     return
        /// }
        ///
        /// // when PropertyType is a reference type 
        /// private void MemberSetter(object target, object value) {
        ///     if ((AllwNull && (null == value)) || (value is PropertyType)) { 
        ///         ((TargetType)target).PropertyName = ((PropertyType)value); 
        ///         return;
        ///     } 
        ///     ThrowInvalidValue(value, TargetType.Name, PropertyName);
        ///     return
        /// }
        ///  
        /// 
        /// If the method is missing or static or has indexed parameters. 
        /// Or if the delcaring type is a value type. 
        /// Or if the parameter type is a pointer.
        /// Or if the method or declaring class has a . 
        /// 
        private static Action CreatePropertySetter(RuntimeMethodHandle rmh, bool allowNull)
        {
            MethodInfo mi; 
            Type realType;
            ValidateSetterProperty(rmh, out mi, out realType); 
 
            // the setter always skips visibility so that we can call our internal method to handle errors
            // because CreateDynamicMethod asserts ReflectionPermission, method is "elevated" and must be treated carefully 
            DynamicMethod method = CreateDynamicMethod(mi.Name, typeof(void), new Type[] { typeof(object), typeof(object) });
            ILGenerator gen = method.GetILGenerator();
            GenerateNecessaryPermissionDemands(gen, mi);
 
            Type elementType = realType;
            Label labelContinueNull = gen.DefineLabel(); 
            Label labelContinueValue = gen.DefineLabel(); 
            Label labelInvalidValue = gen.DefineLabel();
            if (realType.IsValueType) 
            {
                if (realType.IsGenericType && (typeof(Nullable<>) == realType.GetGenericTypeDefinition()))
                {
                    elementType = realType.GetGenericArguments()[0]; 
                }
                else 
                {   // force allowNull false for non-nullable value types 
                    allowNull = false;
                } 
            }

            // ((TargetType)instance)
            gen.Emit(OpCodes.Ldarg_0); 
            gen.Emit(OpCodes.Castclass, mi.DeclaringType);
 
            // if (value is elementType) { 
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Isinst, elementType); 

            if (allowNull)
            {   // reference type or nullable type
                gen.Emit(OpCodes.Ldarg_1); 
                if (elementType == realType)
                { 
                    gen.Emit(OpCodes.Brfalse_S, labelContinueNull);             // if (null == 
                }
                else 
                {
                    gen.Emit(OpCodes.Brtrue, labelContinueValue);
                    gen.Emit(OpCodes.Pop);                                      // pop Isinst
 
                    LocalBuilder local = gen.DeclareLocal(realType);
                    gen.Emit(OpCodes.Ldloca_S, local);                          // load valuetype& 
                    gen.Emit(OpCodes.Initobj, realType);                        // init & 
                    gen.Emit(OpCodes.Ldloc_0);                                  // load valuetype
                    gen.Emit(OpCodes.Br_S, labelContinueNull); 
                    gen.MarkLabel(labelContinueValue);
                }
            }
            gen.Emit(OpCodes.Dup); 
            gen.Emit(OpCodes.Brfalse_S, labelInvalidValue);                     // (arg1 is Inst)
 
            if (elementType.IsValueType) 
            {
                gen.Emit(OpCodes.Unbox_Any, elementType);                       // ((PropertyType)value) 

                if (elementType != realType)
                {                                                               // new Nullable
                    gen.Emit(OpCodes.Newobj, realType.GetConstructor(new Type[] { elementType })); 
                }
            } 
            gen.MarkLabel(labelContinueNull); 
            gen.Emit(mi.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, mi);       // .Property =
            gen.Emit(OpCodes.Ret); 

            // ThrowInvalidValue(value, typeof(PropertyType), DeclaringType.Name, PropertyName
            gen.MarkLabel(labelInvalidValue);
            gen.Emit(OpCodes.Pop);                                      // pop Ldarg_0 
            gen.Emit(OpCodes.Pop);                                      // pop IsInst'
            gen.Emit(OpCodes.Ldarg_1);                                  // determine if InvalidCast or NullReference 
            gen.Emit(OpCodes.Ldtoken, elementType); 
            gen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public));
            gen.Emit(OpCodes.Ldstr, mi.DeclaringType.Name); 
            gen.Emit(OpCodes.Ldstr, mi.Name.Substring(4)); // substring to strip "set_"
            Debug.Assert(null != (Action)EntityUtil.ThrowSetInvalidValue, "missing method ThrowSetInvalidValue(object,Type,string,string)");
            gen.Emit(OpCodes.Call, typeof(EntityUtil).GetMethod("ThrowSetInvalidValue", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(object),typeof(Type),typeof(string),typeof(string)},null));
            gen.Emit(OpCodes.Ret); 
            return (Action)method.CreateDelegate(typeof(Action));
        } 
 
        internal static void ValidateSetterProperty(RuntimeMethodHandle setterMethodHandle, out MethodInfo setterMethodInfo, out Type realType)
        { 
            setterMethodInfo = ((IntPtr.Zero != setterMethodHandle.Value) ? (MethodInfo)MethodBase.GetMethodFromHandle(setterMethodHandle) : null);
            if (null == setterMethodInfo)
            {
                ThrowPropertyNoSetter(); 
            }
            if (setterMethodInfo.IsStatic) 
            { 
                ThrowPropertyIsStatic();
            } 
            if (setterMethodInfo.DeclaringType.IsValueType)
            {
                ThrowPropertyDeclaringTypeIsValueType();
            } 

            ParameterInfo[] parameters = setterMethodInfo.GetParameters(); 
            if ((null == parameters) || (1 != parameters.Length)) 
            {   // if no parameters (i.e. not a set_Property method), will still throw this message
                ThrowPropertyIsIndexed(); 
            }
            realType = setterMethodInfo.ReturnType;
            if ((null != realType) && (typeof(void) != realType))
            { 
                ThrowPropertyUnsupportedForm();
            } 
 
            realType = parameters[0].ParameterType;
            if (realType.IsPointer) 
            {
                ThrowPropertyUnsupportedType();
            }
        } 

        /// Determines if the specified method requires permission demands to be invoked safely. 
        /// Method instance to check. 
        /// true if the specified method requires permission demands to be invoked safely, false otherwise.
        internal static bool RequiresPermissionDemands(MethodBase mi) 
        {
            System.Diagnostics.Debug.Assert(mi != null);
            return !IsPublic(mi) || HasLinkDemand(mi);
        } 

        // Future Enhancement: resolve problem with StrongNameIdentityPermission, demands that only allow specific assemblies to call 
        // 

        private static void GenerateNecessaryPermissionDemands(ILGenerator gen, MethodBase mi) 
        {
            if (HasLinkDemand(mi))
            {   // keep this here, but we are otherwise working around LinkDemands to by using Reflection instead of the DynamicMethod
                gen.Emit(OpCodes.Ldsfld, typeof(LightweightCodeGenerator).GetField("FullTrustPermission", BindingFlags.Static | BindingFlags.NonPublic)); 
                gen.Emit(OpCodes.Callvirt, typeof(NamedPermissionSet).GetMethod("Demand"));
            } 
            else if (!IsPublic(mi)) 
            {
                gen.Emit(OpCodes.Ldsfld, typeof(LightweightCodeGenerator).GetField("MemberAccessReflectionPermission", BindingFlags.Static | BindingFlags.NonPublic)); 
                gen.Emit(OpCodes.Callvirt, typeof(ReflectionPermission).GetMethod("Demand"));
            }
        }
 
        internal static bool HasLinkDemand(MemberInfo info)
        { 
            // we only need link demands directly on the method or class that we invoke 
            // not the link demands on base classes, derived classes, overriden methods ...
            bool result = false; 
            foreach (SecurityAttribute attribute in info.GetCustomAttributes(typeof(SecurityAttribute), false).Concat(
                info.DeclaringType.GetCustomAttributes(typeof(SecurityAttribute), false)))
            {
                if (attribute is StrongNameIdentityPermissionAttribute) 
                {
                    // With StrongNameIdentityPermission, the caller is System.Data.Entity and needs 
                    // to be validated for actual calling assembly. 
                    ThrowPropertyStrongNameIdentity();
                } 
                if (SecurityAction.LinkDemand == attribute.Action)
                {
                    result = true;
                    // do not break or return here, must search all SecurityAttribute for StrongNameIdentityPermission 
                }
            } 
            return result; 
        }
 
        internal static bool IsPublic(MethodBase method)
        {
            return (method.IsPublic && IsPublic(method.DeclaringType));
        } 

        internal static bool IsPublic(Type type) 
        { 
            return ((null == type) || (type.IsPublic && IsPublic(type.DeclaringType)));
        } 

        /// 
        /// Generates a non-generic type version of GetRelatedEnd
        /// Create the code: 
        /// IRelatedEnd GetRelatedEnd(RelationshipManager mgr, RelatedEnd existingRelatedEnd)
        /// { 
        ///     return mgr.GetRelated{Reference|Collection}(of sourceType, targetType)(sourceMember.DeclaringType.FullName, 
        ///                                                                         sourceMember.Name,
        ///                                                                         targetMember.Name, 
        ///                                                                         sourceMember.RelationshipMultiplicity,
        ///                                                                         existingRelatedEnd);
        /// }
        ///  
        /// source end of the relationship for the requested navigation
        /// target end of the relationship for the requested navigation 
        /// Delegate that can be used to call the generated method 
        private static RelationshipManager.GetRelatedEndMethod CreateGetRelatedEndMethod(AssociationEndMember sourceMember, AssociationEndMember targetMember, RelatedEnd existingRelatedEnd)
        { 
            Debug.Assert(sourceMember.DeclaringType == targetMember.DeclaringType, "Source and Target members must be in the same DeclaringType");

            EntityType sourceEntityType = MetadataHelper.GetEntityTypeForEnd(sourceMember);
            Debug.Assert(sourceEntityType.DataSpace == DataSpace.OSpace && sourceEntityType.ClrType != null, "sourceEntityType must contain an ospace type"); 
            Type sourceType = sourceEntityType.ClrType;
            EntityType targetEntityType = MetadataHelper.GetEntityTypeForEnd(targetMember); 
            Debug.Assert(targetEntityType.DataSpace == DataSpace.OSpace && targetEntityType.ClrType != null, "targetEntityType must contain an ospace type"); 
            Type targetType = targetEntityType.ClrType;
 
            // Get the appropriate method, either collection or reference depending on the target multiplicity
            MethodInfo getRelatedItem = null;
            switch (targetMember.RelationshipMultiplicity)
            { 
                case RelationshipMultiplicity.ZeroOrOne:
                case RelationshipMultiplicity.One: 
                    { 
                        // reference
                        MethodInfo getRelatedReferenceGeneric = typeof(RelationshipManager).GetMethod("GetRelatedReference", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(string), typeof(string), typeof(RelationshipMultiplicity), typeof(RelatedEnd) }, null); 
                        if (getRelatedReferenceGeneric == null)
                        {
                            throw EntityUtil.MissingMethod("GetRelatedReference");
                        } 
                        getRelatedItem = getRelatedReferenceGeneric.MakeGenericMethod(sourceType, targetType);
                        break; 
                    } 
                case RelationshipMultiplicity.Many:
                    { 
                        // collection
                        MethodInfo getRelatedCollectionGeneric = typeof(RelationshipManager).GetMethod("GetRelatedCollection", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(string), typeof(string), typeof(RelationshipMultiplicity), typeof(RelatedEnd) }, null);
                        if (getRelatedCollectionGeneric == null)
                        { 
                            throw EntityUtil.MissingMethod("GetRelatedCollection");
                        } 
                        getRelatedItem = getRelatedCollectionGeneric.MakeGenericMethod(sourceType, targetType); 
                        break;
                    } 
                default:
                    throw EntityUtil.InvalidEnumerationValue(typeof(RelationshipMultiplicity), (int)targetMember.RelationshipMultiplicity);
            }
 
            DynamicMethod method = CreateDynamicMethod("GetRelatedEnd", typeof(IRelatedEnd), new Type[] { typeof(RelationshipManager), typeof(RelatedEnd)});
            ILGenerator generator = method.GetILGenerator(); 
            Debug.Assert(getRelatedItem.IsPrivate && !getRelatedItem.IsVirtual && (typeof(RelationshipManager) == getRelatedItem.DeclaringType), "Unexpected characteristics for GetRelatedCollection or GetRelatedReference"); 
            // not generating reflection permission demand for calling RelationshipManager GetRelatedReference or GetRelatedCollection private non-interface methods
 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Castclass, getRelatedItem.DeclaringType);

            generator.Emit(OpCodes.Ldstr, sourceMember.DeclaringType.FullName); 
            generator.Emit(OpCodes.Ldstr, sourceMember.Name);
            generator.Emit(OpCodes.Ldstr, targetMember.Name); 
            switch (sourceMember.RelationshipMultiplicity) 
            {
                case RelationshipMultiplicity.ZeroOrOne: 
                    generator.Emit(OpCodes.Ldc_I4_0); break;
                case RelationshipMultiplicity.One: generator.Emit(OpCodes.Ldc_I4_1); break;
                case RelationshipMultiplicity.Many: generator.Emit(OpCodes.Ldc_I4_2); break;
                default: 
                throw EntityUtil.InvalidEnumerationValue(typeof(RelationshipMultiplicity), (int)sourceMember.RelationshipMultiplicity);
            } 
            generator.Emit(OpCodes.Ldarg_1); 

            generator.Emit(OpCodes.Call, getRelatedItem); 
            generator.Emit(OpCodes.Ret);

            RelationshipManager.GetRelatedEndMethod getRelatedEndMethod = (RelationshipManager.GetRelatedEndMethod)method.CreateDelegate(typeof(RelationshipManager.GetRelatedEndMethod));
 
            return getRelatedEndMethod;
        } 
 
        private static void ThrowConstructorNoParameterless()
        { 
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_ConstructorNoParameterless);
        }
        private static void ThrowPropertyDeclaringTypeIsValueType()
        { 
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyDeclaringTypeIsValueType);
        } 
        private static void ThrowPropertyUnsupportedForm() 
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyUnsupportedForm); 
        }
        private static void ThrowPropertyUnsupportedType()
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyUnsupportedType); 
        }
        private static void ThrowPropertyStrongNameIdentity() 
        { 
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyStrongNameIdentity);
        } 
        private static void ThrowPropertyIsIndexed()
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyIsIndexed);
        } 
        private static void ThrowPropertyIsStatic()
        { 
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyIsStatic); 
        }
        private static void ThrowPropertyNoGetter() 
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyNoGetter);
        }
        private static void ThrowPropertyNoSetter() 
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyNoSetter); 
        } 

        #endregion 

        #region Lightweight code generation

        internal static readonly ReflectionPermission MemberAccessReflectionPermission = new ReflectionPermission(ReflectionPermissionFlag.MemberAccess); 
        internal static readonly NamedPermissionSet FullTrustPermission = new NamedPermissionSet("FullTrust");
 
        // we could cache more, like 'new Type[] { ... }' and 'typeof(object)' 
        // but pruned as much as possible for the workingset helps, even little things
 
        // assert MemberAccess to skip visbility check & ReflectionEmit so we can generate the method
        [System.Security.SecurityCritical]
        [System.Security.SecurityTreatAsSafe]
        [ReflectionPermission(SecurityAction.Assert, MemberAccess = true, ReflectionEmit = true)] 
        private static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes)
        { 
            // Consider: write unit test to verify assumptions for why we don't use security transparent dynamic method (new in orcas) 
            //       expecation is the security for the transparent jitted method is fixed on for the fist caller
            //       and we reuse the delegate for all callers 
            return new DynamicMethod(name, returnType, parameterTypes, typeof(LightweightCodeGenerator).Module, true);
        }

        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

namespace System.Data.Objects 
{
    using System;
    using System.Data.Metadata.Edm;
    using System.Diagnostics; 
    using System.Reflection;
    using System.Reflection.Emit; 
    using System.Security; 
    using System.Security.Permissions;
    using System.Data.Objects.DataClasses; 
    using System.Data.Common.Utils;
    using System.Linq;

    ///  
    /// CodeGenerator class: use lightweight code gen to dynamically generate code to get/set properties.
    ///  
    internal static class LightweightCodeGenerator 
    {
 
        /// For an OSpace ComplexType or EntityType, returns the delegate to construct the clr instance.
        internal static Delegate GetConstructorDelegateForType(EdmType clrType)
        {
            return (Helper.IsEntityType(clrType) 
                    ? GetConstructorDelegateForType((ClrEntityType)clrType)
                    : GetConstructorDelegateForType((ClrComplexType)clrType)); 
        } 

        /// For an OSpace ComplexType or EntityType, returns the delegate to construct the clr instance. 
        internal static Delegate GetConstructorDelegateForType(ClrEntityType clrType)
        {
            return (clrType.Constructor ?? (clrType.Constructor = CreateEntityConstructor(clrType.ClrType)));
        } 

        internal static Delegate GetConstructorDelegateForType(ClrComplexType clrType) 
        { 
            return (clrType.Constructor ?? (clrType.Constructor = CreateConstructor(clrType.ClrType)));
        } 

        /// for an OSpace property, get the property value from a clr instance
        internal static object GetValue(NavigationProperty property, object target)
        { 
            Func getter = property.ValueGetter;
            if (null == getter) 
            { 
                getter = CreatePropertyGetter(property.PropertyGetterHandle);
                property.ValueGetter = getter; 
            }
            Debug.Assert(null != getter, "null getter");

            //Not tracing every property get 
            //EntityBid.Trace(" Name='%ls'\n", property.Name);
            return getter(target); 
        } 

        /// for an OSpace property, get the property value from a clr instance 
        internal static object GetValue(EdmProperty property, object target)
        {
            Func getter = GetGetterDelegateForProperty(property);
            Debug.Assert(null != getter, "null getter"); 

            //Not tracing every property get 
            //EntityBid.Trace(" Name='%ls'\n", property.Name); 
            return getter(target);
        } 

        internal static Func GetGetterDelegateForProperty(EdmProperty property)
        {
            return property.ValueGetter ?? (property.ValueGetter = CreatePropertyGetter(property.PropertyGetterHandle)); 
        }
 
        /// for an OSpace property, set the property value on a clr instance 
        /// 
        /// If  is null for a non nullable property. 
        /// 
        /// 
        /// Invalid cast of  to property type.
        ///  
        /// 
        /// From generated enties via StructuralObject.SetValidValue. 
        ///  
        /// 
        /// If the property setter is not public or declaring class is not public. 
        /// 
        /// 
        /// Demand for FullTrust if the property setter or declaring class has a 
        ///  
        internal static void SetValue(EdmProperty property, object target, object value)
        { 
            Action setter = GetSetterDelegateForProperty(property); 
            if (Bid.TraceOn)
            { 
                EntityBid.Trace(" Name='%ls'\n", property.Name);
            }
            setter(target, value);
        } 

        /// For an OSpace property, gets the delegate to set the property value on a clr instance. 
        internal static Action GetSetterDelegateForProperty(EdmProperty property) 
        {
            Action setter = property.ValueSetter; 
            if (null == setter)
            {
                setter = CreatePropertySetter(property.PropertySetterHandle,
                        property.Nullable); 
                property.ValueSetter = setter;
            } 
            Debug.Assert(null != setter, "null setter"); 
            return setter;
        } 

        /// 
        /// Gets the related end instance for the source AssociationEndMember by creating a DynamicMethod to
        /// call GetRelatedCollection or GetRelatedReference 
        /// 
        internal static IRelatedEnd GetRelatedEnd(RelationshipManager sourceRelationshipManager, AssociationEndMember sourceMember, AssociationEndMember targetMember, RelatedEnd existingRelatedEnd) 
        { 
            RelationshipManager.GetRelatedEndMethod getRelatedEnd = sourceMember.GetRelatedEnd as RelationshipManager.GetRelatedEndMethod;
            if (null == getRelatedEnd) 
            {
                getRelatedEnd = CreateGetRelatedEndMethod(sourceMember, targetMember, existingRelatedEnd);
                sourceMember.GetRelatedEnd = getRelatedEnd;
            } 
            Debug.Assert(null != getRelatedEnd, "null getRelatedEnd");
 
            //Not tracing every property get 
            //EntityBid.Trace(" Name='%ls'\n", property.Name);
            return getRelatedEnd(sourceRelationshipManager, existingRelatedEnd); 
        }

        #region get the delegate
 
        /// Gets a parameterless constructor for the specified type.
        /// Type to get constructor for. 
        /// Parameterless constructor for the specified type. 
        internal static ConstructorInfo GetConstructorForType(Type type)
        { 
            System.Diagnostics.Debug.Assert(type != null);
            ConstructorInfo ci = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, System.Type.EmptyTypes, null);
            if (null == ci)
            { 
                ThrowConstructorNoParameterless();
            } 
            return ci; 
        }
 

        /// 
        /// generate a delegate equivalent to
        /// private object Constructor() { return new XClass(); } 
        /// 
        private static Delegate CreateConstructor(Type type) 
        { 
            ConstructorInfo ci = GetConstructorForType(type);
 
            // because CreateDynamicMethod asserts ReflectionPermission, method is "elevated" and must be treated carefully
            DynamicMethod method = CreateDynamicMethod(ci.DeclaringType.Name, typeof(object), Type.EmptyTypes);
            ILGenerator gen = method.GetILGenerator();
            GenerateNecessaryPermissionDemands(gen, ci); 

            gen.Emit(OpCodes.Newobj, ci); 
            gen.Emit(OpCodes.Ret); 
            return method.CreateDelegate(typeof(Func));
        } 

        /// 
        /// generate a delegate equivalent to
        /// private object Constructor(EntityKey, ObjectContext, EntitySet, MergeOption) { 
        ///    object value = new XClass();
        /// 
        ///    if (null != entityKey) { 
        ///      #if XClass implements IEntityKey
        ///      ((IEntityWithKey)this).EntityKey = entityKey; 
        ///      #endif
        ///
        ///      #if XClass implements IEntityWithRelationships
        ///      RelationshipManager manager = ((IEntityWithRelationships)this).RelationshipManager; 
        ///      if (null != manager) { manager.AttachContext(ObjectContext, EntitySet, MergeOption); }
        ///    } 
        /// 
        ///    return value;
        /// return new XClass(); } 
        /// 
        private static Delegate CreateEntityConstructor(Type type)
        {
            ConstructorInfo ci = GetConstructorForType(type); 

            // because CreateDynamicMethod asserts ReflectionPermission, method is "elevated" and must be treated carefully 
            DynamicMethod method = CreateDynamicMethod(ci.DeclaringType.Name, typeof(object), new Type[] { typeof(EntityKey), typeof(ObjectContext), typeof(EntitySet), typeof(MergeOption) }); 
            ILGenerator gen = method.GetILGenerator();
            GenerateNecessaryPermissionDemands(gen, ci); 

            gen.Emit(OpCodes.Newobj, ci);

            bool withKey = typeof(IEntityWithKey).IsAssignableFrom(type); 
            bool withRel = typeof(IEntityWithRelationships).IsAssignableFrom(type);
 
            if (withKey || withRel) 
            {
                Label nullEntityKey = gen.DefineLabel(); 
                gen.Emit(OpCodes.Ldarg_0);                  // EntityKey
                gen.Emit(OpCodes.Brfalse_S, nullEntityKey); // null EntityKey

                if (withKey) 
                {
                    gen.Emit(OpCodes.Dup);                      // the Newobj 
                    gen.Emit(OpCodes.Castclass, typeof(IEntityWithKey)); 
                    gen.Emit(OpCodes.Ldarg_0);                  // EntityKey
                    gen.Emit(OpCodes.Callvirt, typeof(IEntityWithKey).GetMethod("set_EntityKey", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(EntityKey) }, null)); 
                }

                // The only reason we would call RelationshipManager.AttachContext would be to enable loading related entities,
                // but if there’s no entitykey (aka NoEntitySetKey), then there’s no way that should work. 
                // So it’s reasonable not to call RelationshipManager.AttachContext unless there is a valid EntityKey
                if (withRel) 
                { 
                    Label nullContext = gen.DefineLabel();
 
                    gen.Emit(OpCodes.Ldarg_1);                  // ObjectContext
                    gen.Emit(OpCodes.Brfalse_S, nullContext);   // null context, don't AttachContext

                    gen.Emit(OpCodes.Dup);                      // the Newobj 
                    gen.Emit(OpCodes.Castclass, typeof(IEntityWithRelationships));
                    gen.Emit(OpCodes.Ldarg_1);                  // ObjectContext 
                    gen.Emit(OpCodes.Ldarg_2);                  // EntitySet 
                    gen.Emit(OpCodes.Ldarg_3);                  // MergeOption
 
                    Debug.Assert(null != (Action)EntityUtil.AttachContext, "missing method AttachContext(IEntityWithRelationships, ObjectContext, EntitySet, MergeOption)");
                    gen.Emit(OpCodes.Call, typeof(EntityUtil).GetMethod("AttachContext", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(IEntityWithRelationships), typeof(ObjectContext), typeof(EntitySet), typeof(MergeOption) }, null));

                    gen.MarkLabel(nullContext); 
                }
                gen.MarkLabel(nullEntityKey); 
            } 

            gen.Emit(OpCodes.Ret); 
            return method.CreateDelegate(typeof(Func));
        }

        ///  
        /// generate a delegate equivalent to
        /// private object MemberGetter(object target) { return target.PropertyX; } 
        /// or if the property is Nullable<> generate a delegate equivalent to 
        /// private object MemberGetter(object target) { Nullable y = target.PropertyX; return ((y.HasValue) ? y.Value : null); }
        ///  
        private static Func CreatePropertyGetter(RuntimeMethodHandle rmh)
        {
            MethodInfo mi = ((IntPtr.Zero != rmh.Value) ? (MethodInfo)MethodBase.GetMethodFromHandle(rmh) : null);
            if (null == mi) 
            {
                ThrowPropertyNoGetter(); 
            } 
            if (mi.IsStatic)
            { 
                ThrowPropertyIsStatic();
            }
            if (mi.DeclaringType.IsValueType)
            { 
                ThrowPropertyDeclaringTypeIsValueType();
            } 
 
            if (0 != mi.GetParameters().Length)
            { 
                ThrowPropertyIsIndexed();
            }

            Type realType = mi.ReturnType; 
            if ((null == realType) || (typeof(void) == realType))
            { 
                ThrowPropertyUnsupportedForm(); 
            }
            if (realType.IsPointer) 
            {
                ThrowPropertyUnsupportedType();
            }
 
            // because CreateDynamicMethod asserts ReflectionPermission, method is "elevated" and must be treated carefully
            DynamicMethod method = CreateDynamicMethod(mi.Name, typeof(object), new Type[] { typeof(object) }); 
            ILGenerator gen = method.GetILGenerator(); 
            GenerateNecessaryPermissionDemands(gen, mi);
 
            // the 'this' target pointer
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, mi.DeclaringType);
            gen.Emit(mi.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, mi); 

            if (realType.IsValueType) 
            { 
                Type elementType;
                if (realType.IsGenericType && (typeof(Nullable<>) == realType.GetGenericTypeDefinition())) 
                {
                    elementType = realType.GetGenericArguments()[0];

                    Label lableFalse = gen.DefineLabel(); 
                    LocalBuilder local = gen.DeclareLocal(realType);
                    gen.Emit(OpCodes.Stloc_S, local); 
 
                    gen.Emit(OpCodes.Ldloca_S, local);
                    gen.Emit(OpCodes.Call, realType.GetMethod("get_HasValue")); 
                    gen.Emit(OpCodes.Brfalse_S, lableFalse);

                    gen.Emit(OpCodes.Ldloca_S, local);
                    gen.Emit(OpCodes.Call, realType.GetMethod("get_Value")); 
                    gen.Emit(OpCodes.Box, elementType = realType.GetGenericArguments()[0]);
                    gen.Emit(OpCodes.Ret); 
 
                    gen.MarkLabel(lableFalse);
                    gen.Emit(OpCodes.Ldnull); 
                }
                else
                {
                    // need to box to return value as object 
                    elementType = realType;
                    gen.Emit(OpCodes.Box, elementType); 
                } 
            }
            gen.Emit(OpCodes.Ret); 
            return (Func)method.CreateDelegate(typeof(Func));
        }

        ///  
        /// generate a delegate equivalent to
        /// 
        /// // if Property is Nullable value type 
        /// private void MemberSetter(object target, object value) {
        ///     if (AllwNull && (null == value)) { 
        ///         ((TargetType)target).PropertyName = default(PropertyType?);
        ///         return;
        ///     }
        ///     if (value is PropertyType) { 
        ///             ((TargetType)target).PropertyName = new (PropertyType?)((PropertyType)value);
        ///         return; 
        ///     } 
        ///     ThrowInvalidValue(value, TargetType.Name, PropertyName);
        ///     return 
        /// }
        ///
        /// // when PropertyType is a value type
        /// private void MemberSetter(object target, object value) { 
        ///     if (value is PropertyType) {
        ///             ((TargetType)target).PropertyName = (PropertyType)value; 
        ///         return; 
        ///     }
        ///     ThrowInvalidValue(value, TargetType.Name, PropertyName); 
        ///     return
        /// }
        ///
        /// // when PropertyType is a reference type 
        /// private void MemberSetter(object target, object value) {
        ///     if ((AllwNull && (null == value)) || (value is PropertyType)) { 
        ///         ((TargetType)target).PropertyName = ((PropertyType)value); 
        ///         return;
        ///     } 
        ///     ThrowInvalidValue(value, TargetType.Name, PropertyName);
        ///     return
        /// }
        ///  
        /// 
        /// If the method is missing or static or has indexed parameters. 
        /// Or if the delcaring type is a value type. 
        /// Or if the parameter type is a pointer.
        /// Or if the method or declaring class has a . 
        /// 
        private static Action CreatePropertySetter(RuntimeMethodHandle rmh, bool allowNull)
        {
            MethodInfo mi; 
            Type realType;
            ValidateSetterProperty(rmh, out mi, out realType); 
 
            // the setter always skips visibility so that we can call our internal method to handle errors
            // because CreateDynamicMethod asserts ReflectionPermission, method is "elevated" and must be treated carefully 
            DynamicMethod method = CreateDynamicMethod(mi.Name, typeof(void), new Type[] { typeof(object), typeof(object) });
            ILGenerator gen = method.GetILGenerator();
            GenerateNecessaryPermissionDemands(gen, mi);
 
            Type elementType = realType;
            Label labelContinueNull = gen.DefineLabel(); 
            Label labelContinueValue = gen.DefineLabel(); 
            Label labelInvalidValue = gen.DefineLabel();
            if (realType.IsValueType) 
            {
                if (realType.IsGenericType && (typeof(Nullable<>) == realType.GetGenericTypeDefinition()))
                {
                    elementType = realType.GetGenericArguments()[0]; 
                }
                else 
                {   // force allowNull false for non-nullable value types 
                    allowNull = false;
                } 
            }

            // ((TargetType)instance)
            gen.Emit(OpCodes.Ldarg_0); 
            gen.Emit(OpCodes.Castclass, mi.DeclaringType);
 
            // if (value is elementType) { 
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Isinst, elementType); 

            if (allowNull)
            {   // reference type or nullable type
                gen.Emit(OpCodes.Ldarg_1); 
                if (elementType == realType)
                { 
                    gen.Emit(OpCodes.Brfalse_S, labelContinueNull);             // if (null == 
                }
                else 
                {
                    gen.Emit(OpCodes.Brtrue, labelContinueValue);
                    gen.Emit(OpCodes.Pop);                                      // pop Isinst
 
                    LocalBuilder local = gen.DeclareLocal(realType);
                    gen.Emit(OpCodes.Ldloca_S, local);                          // load valuetype& 
                    gen.Emit(OpCodes.Initobj, realType);                        // init & 
                    gen.Emit(OpCodes.Ldloc_0);                                  // load valuetype
                    gen.Emit(OpCodes.Br_S, labelContinueNull); 
                    gen.MarkLabel(labelContinueValue);
                }
            }
            gen.Emit(OpCodes.Dup); 
            gen.Emit(OpCodes.Brfalse_S, labelInvalidValue);                     // (arg1 is Inst)
 
            if (elementType.IsValueType) 
            {
                gen.Emit(OpCodes.Unbox_Any, elementType);                       // ((PropertyType)value) 

                if (elementType != realType)
                {                                                               // new Nullable
                    gen.Emit(OpCodes.Newobj, realType.GetConstructor(new Type[] { elementType })); 
                }
            } 
            gen.MarkLabel(labelContinueNull); 
            gen.Emit(mi.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, mi);       // .Property =
            gen.Emit(OpCodes.Ret); 

            // ThrowInvalidValue(value, typeof(PropertyType), DeclaringType.Name, PropertyName
            gen.MarkLabel(labelInvalidValue);
            gen.Emit(OpCodes.Pop);                                      // pop Ldarg_0 
            gen.Emit(OpCodes.Pop);                                      // pop IsInst'
            gen.Emit(OpCodes.Ldarg_1);                                  // determine if InvalidCast or NullReference 
            gen.Emit(OpCodes.Ldtoken, elementType); 
            gen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public));
            gen.Emit(OpCodes.Ldstr, mi.DeclaringType.Name); 
            gen.Emit(OpCodes.Ldstr, mi.Name.Substring(4)); // substring to strip "set_"
            Debug.Assert(null != (Action)EntityUtil.ThrowSetInvalidValue, "missing method ThrowSetInvalidValue(object,Type,string,string)");
            gen.Emit(OpCodes.Call, typeof(EntityUtil).GetMethod("ThrowSetInvalidValue", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(object),typeof(Type),typeof(string),typeof(string)},null));
            gen.Emit(OpCodes.Ret); 
            return (Action)method.CreateDelegate(typeof(Action));
        } 
 
        internal static void ValidateSetterProperty(RuntimeMethodHandle setterMethodHandle, out MethodInfo setterMethodInfo, out Type realType)
        { 
            setterMethodInfo = ((IntPtr.Zero != setterMethodHandle.Value) ? (MethodInfo)MethodBase.GetMethodFromHandle(setterMethodHandle) : null);
            if (null == setterMethodInfo)
            {
                ThrowPropertyNoSetter(); 
            }
            if (setterMethodInfo.IsStatic) 
            { 
                ThrowPropertyIsStatic();
            } 
            if (setterMethodInfo.DeclaringType.IsValueType)
            {
                ThrowPropertyDeclaringTypeIsValueType();
            } 

            ParameterInfo[] parameters = setterMethodInfo.GetParameters(); 
            if ((null == parameters) || (1 != parameters.Length)) 
            {   // if no parameters (i.e. not a set_Property method), will still throw this message
                ThrowPropertyIsIndexed(); 
            }
            realType = setterMethodInfo.ReturnType;
            if ((null != realType) && (typeof(void) != realType))
            { 
                ThrowPropertyUnsupportedForm();
            } 
 
            realType = parameters[0].ParameterType;
            if (realType.IsPointer) 
            {
                ThrowPropertyUnsupportedType();
            }
        } 

        /// Determines if the specified method requires permission demands to be invoked safely. 
        /// Method instance to check. 
        /// true if the specified method requires permission demands to be invoked safely, false otherwise.
        internal static bool RequiresPermissionDemands(MethodBase mi) 
        {
            System.Diagnostics.Debug.Assert(mi != null);
            return !IsPublic(mi) || HasLinkDemand(mi);
        } 

        // Future Enhancement: resolve problem with StrongNameIdentityPermission, demands that only allow specific assemblies to call 
        // 

        private static void GenerateNecessaryPermissionDemands(ILGenerator gen, MethodBase mi) 
        {
            if (HasLinkDemand(mi))
            {   // keep this here, but we are otherwise working around LinkDemands to by using Reflection instead of the DynamicMethod
                gen.Emit(OpCodes.Ldsfld, typeof(LightweightCodeGenerator).GetField("FullTrustPermission", BindingFlags.Static | BindingFlags.NonPublic)); 
                gen.Emit(OpCodes.Callvirt, typeof(NamedPermissionSet).GetMethod("Demand"));
            } 
            else if (!IsPublic(mi)) 
            {
                gen.Emit(OpCodes.Ldsfld, typeof(LightweightCodeGenerator).GetField("MemberAccessReflectionPermission", BindingFlags.Static | BindingFlags.NonPublic)); 
                gen.Emit(OpCodes.Callvirt, typeof(ReflectionPermission).GetMethod("Demand"));
            }
        }
 
        internal static bool HasLinkDemand(MemberInfo info)
        { 
            // we only need link demands directly on the method or class that we invoke 
            // not the link demands on base classes, derived classes, overriden methods ...
            bool result = false; 
            foreach (SecurityAttribute attribute in info.GetCustomAttributes(typeof(SecurityAttribute), false).Concat(
                info.DeclaringType.GetCustomAttributes(typeof(SecurityAttribute), false)))
            {
                if (attribute is StrongNameIdentityPermissionAttribute) 
                {
                    // With StrongNameIdentityPermission, the caller is System.Data.Entity and needs 
                    // to be validated for actual calling assembly. 
                    ThrowPropertyStrongNameIdentity();
                } 
                if (SecurityAction.LinkDemand == attribute.Action)
                {
                    result = true;
                    // do not break or return here, must search all SecurityAttribute for StrongNameIdentityPermission 
                }
            } 
            return result; 
        }
 
        internal static bool IsPublic(MethodBase method)
        {
            return (method.IsPublic && IsPublic(method.DeclaringType));
        } 

        internal static bool IsPublic(Type type) 
        { 
            return ((null == type) || (type.IsPublic && IsPublic(type.DeclaringType)));
        } 

        /// 
        /// Generates a non-generic type version of GetRelatedEnd
        /// Create the code: 
        /// IRelatedEnd GetRelatedEnd(RelationshipManager mgr, RelatedEnd existingRelatedEnd)
        /// { 
        ///     return mgr.GetRelated{Reference|Collection}(of sourceType, targetType)(sourceMember.DeclaringType.FullName, 
        ///                                                                         sourceMember.Name,
        ///                                                                         targetMember.Name, 
        ///                                                                         sourceMember.RelationshipMultiplicity,
        ///                                                                         existingRelatedEnd);
        /// }
        ///  
        /// source end of the relationship for the requested navigation
        /// target end of the relationship for the requested navigation 
        /// Delegate that can be used to call the generated method 
        private static RelationshipManager.GetRelatedEndMethod CreateGetRelatedEndMethod(AssociationEndMember sourceMember, AssociationEndMember targetMember, RelatedEnd existingRelatedEnd)
        { 
            Debug.Assert(sourceMember.DeclaringType == targetMember.DeclaringType, "Source and Target members must be in the same DeclaringType");

            EntityType sourceEntityType = MetadataHelper.GetEntityTypeForEnd(sourceMember);
            Debug.Assert(sourceEntityType.DataSpace == DataSpace.OSpace && sourceEntityType.ClrType != null, "sourceEntityType must contain an ospace type"); 
            Type sourceType = sourceEntityType.ClrType;
            EntityType targetEntityType = MetadataHelper.GetEntityTypeForEnd(targetMember); 
            Debug.Assert(targetEntityType.DataSpace == DataSpace.OSpace && targetEntityType.ClrType != null, "targetEntityType must contain an ospace type"); 
            Type targetType = targetEntityType.ClrType;
 
            // Get the appropriate method, either collection or reference depending on the target multiplicity
            MethodInfo getRelatedItem = null;
            switch (targetMember.RelationshipMultiplicity)
            { 
                case RelationshipMultiplicity.ZeroOrOne:
                case RelationshipMultiplicity.One: 
                    { 
                        // reference
                        MethodInfo getRelatedReferenceGeneric = typeof(RelationshipManager).GetMethod("GetRelatedReference", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(string), typeof(string), typeof(RelationshipMultiplicity), typeof(RelatedEnd) }, null); 
                        if (getRelatedReferenceGeneric == null)
                        {
                            throw EntityUtil.MissingMethod("GetRelatedReference");
                        } 
                        getRelatedItem = getRelatedReferenceGeneric.MakeGenericMethod(sourceType, targetType);
                        break; 
                    } 
                case RelationshipMultiplicity.Many:
                    { 
                        // collection
                        MethodInfo getRelatedCollectionGeneric = typeof(RelationshipManager).GetMethod("GetRelatedCollection", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(string), typeof(string), typeof(RelationshipMultiplicity), typeof(RelatedEnd) }, null);
                        if (getRelatedCollectionGeneric == null)
                        { 
                            throw EntityUtil.MissingMethod("GetRelatedCollection");
                        } 
                        getRelatedItem = getRelatedCollectionGeneric.MakeGenericMethod(sourceType, targetType); 
                        break;
                    } 
                default:
                    throw EntityUtil.InvalidEnumerationValue(typeof(RelationshipMultiplicity), (int)targetMember.RelationshipMultiplicity);
            }
 
            DynamicMethod method = CreateDynamicMethod("GetRelatedEnd", typeof(IRelatedEnd), new Type[] { typeof(RelationshipManager), typeof(RelatedEnd)});
            ILGenerator generator = method.GetILGenerator(); 
            Debug.Assert(getRelatedItem.IsPrivate && !getRelatedItem.IsVirtual && (typeof(RelationshipManager) == getRelatedItem.DeclaringType), "Unexpected characteristics for GetRelatedCollection or GetRelatedReference"); 
            // not generating reflection permission demand for calling RelationshipManager GetRelatedReference or GetRelatedCollection private non-interface methods
 
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Castclass, getRelatedItem.DeclaringType);

            generator.Emit(OpCodes.Ldstr, sourceMember.DeclaringType.FullName); 
            generator.Emit(OpCodes.Ldstr, sourceMember.Name);
            generator.Emit(OpCodes.Ldstr, targetMember.Name); 
            switch (sourceMember.RelationshipMultiplicity) 
            {
                case RelationshipMultiplicity.ZeroOrOne: 
                    generator.Emit(OpCodes.Ldc_I4_0); break;
                case RelationshipMultiplicity.One: generator.Emit(OpCodes.Ldc_I4_1); break;
                case RelationshipMultiplicity.Many: generator.Emit(OpCodes.Ldc_I4_2); break;
                default: 
                throw EntityUtil.InvalidEnumerationValue(typeof(RelationshipMultiplicity), (int)sourceMember.RelationshipMultiplicity);
            } 
            generator.Emit(OpCodes.Ldarg_1); 

            generator.Emit(OpCodes.Call, getRelatedItem); 
            generator.Emit(OpCodes.Ret);

            RelationshipManager.GetRelatedEndMethod getRelatedEndMethod = (RelationshipManager.GetRelatedEndMethod)method.CreateDelegate(typeof(RelationshipManager.GetRelatedEndMethod));
 
            return getRelatedEndMethod;
        } 
 
        private static void ThrowConstructorNoParameterless()
        { 
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_ConstructorNoParameterless);
        }
        private static void ThrowPropertyDeclaringTypeIsValueType()
        { 
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyDeclaringTypeIsValueType);
        } 
        private static void ThrowPropertyUnsupportedForm() 
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyUnsupportedForm); 
        }
        private static void ThrowPropertyUnsupportedType()
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyUnsupportedType); 
        }
        private static void ThrowPropertyStrongNameIdentity() 
        { 
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyStrongNameIdentity);
        } 
        private static void ThrowPropertyIsIndexed()
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyIsIndexed);
        } 
        private static void ThrowPropertyIsStatic()
        { 
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyIsStatic); 
        }
        private static void ThrowPropertyNoGetter() 
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyNoGetter);
        }
        private static void ThrowPropertyNoSetter() 
        {
            throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.CodeGen_PropertyNoSetter); 
        } 

        #endregion 

        #region Lightweight code generation

        internal static readonly ReflectionPermission MemberAccessReflectionPermission = new ReflectionPermission(ReflectionPermissionFlag.MemberAccess); 
        internal static readonly NamedPermissionSet FullTrustPermission = new NamedPermissionSet("FullTrust");
 
        // we could cache more, like 'new Type[] { ... }' and 'typeof(object)' 
        // but pruned as much as possible for the workingset helps, even little things
 
        // assert MemberAccess to skip visbility check & ReflectionEmit so we can generate the method
        [System.Security.SecurityCritical]
        [System.Security.SecurityTreatAsSafe]
        [ReflectionPermission(SecurityAction.Assert, MemberAccess = true, ReflectionEmit = true)] 
        private static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes)
        { 
            // Consider: write unit test to verify assumptions for why we don't use security transparent dynamic method (new in orcas) 
            //       expecation is the security for the transparent jitted method is fixed on for the fist caller
            //       and we reuse the delegate for all callers 
            return new DynamicMethod(name, returnType, parameterTypes, typeof(LightweightCodeGenerator).Module, true);
        }

        #endregion 
    }
} 

// 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