1 //---------------------------------------------------------------------
2 // <copyright file="EntityProxyFactory.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //---------------------------------------------------------------------
10 namespace System.Data.Objects.Internal
13 using System.Collections.Generic;
14 using System.ComponentModel;
15 using System.Data.Common.Utils;
16 using System.Data.Metadata.Edm;
17 using System.Data.Objects.DataClasses;
18 using System.Diagnostics;
19 using System.Globalization;
21 using System.Linq.Expressions;
22 using System.Reflection;
23 using System.Reflection.Emit;
24 using System.Runtime.CompilerServices;
25 using System.Runtime.Serialization;
26 using System.Security;
27 using System.Security.Permissions;
28 using System.Threading;
31 /// Factory for creating proxy classes that can intercept calls to a class' members.
33 internal class EntityProxyFactory
35 private const string ProxyTypeNameFormat = "System.Data.Entity.DynamicProxies.{0}_{1}";
36 internal const string ResetFKSetterFlagFieldName = "_resetFKSetterFlag";
37 internal const string CompareByteArraysFieldName = "_compareByteArrays";
40 /// A hook such that test code can change the AssemblyBuilderAccess of the
41 /// proxy assembly through reflection into the EntityProxyFactory.
43 private static AssemblyBuilderAccess s_ProxyAssemblyBuilderAccess = AssemblyBuilderAccess.Run;
45 /// Dictionary of proxy class type information, keyed by the pair of the CLR type and EntityType CSpaceName of the type being proxied.
46 /// A null value for a particular EntityType name key records the fact that
47 /// no proxy Type could be created for the specified type.
49 private static Dictionary<Tuple<Type, string>, EntityProxyTypeInfo> s_ProxyNameMap = new Dictionary<Tuple<Type, string>, EntityProxyTypeInfo>();
51 /// Dictionary of proxy class type information, keyed by the proxy type
53 private static Dictionary<Type, EntityProxyTypeInfo> s_ProxyTypeMap = new Dictionary<Type, EntityProxyTypeInfo>();
54 private static Dictionary<Assembly, ModuleBuilder> s_ModuleBuilders = new Dictionary<Assembly, ModuleBuilder>();
55 private static ReaderWriterLockSlim s_TypeMapLock = new ReaderWriterLockSlim();
58 /// The runtime assembly of the proxy types.
59 /// This is not the same as the AssemblyBuilder used to create proxy types.
61 private static HashSet<Assembly> ProxyRuntimeAssemblies = new HashSet<Assembly>();
63 private static ModuleBuilder GetDynamicModule(EntityType ospaceEntityType)
65 Assembly assembly = ospaceEntityType.ClrType.Assembly;
66 ModuleBuilder moduleBuilder;
67 if (!s_ModuleBuilders.TryGetValue(assembly, out moduleBuilder))
69 AssemblyName assemblyName = new AssemblyName(String.Format(CultureInfo.InvariantCulture, "EntityFrameworkDynamicProxies-{0}", assembly.FullName));
70 assemblyName.Version = new Version(1, 0, 0, 0);
72 // Mark assembly as security transparent, meaning it cannot cause an elevation of privilege.
73 // This also means the assembly cannot satisfy a link demand. Instead link demands become full demands.
74 ConstructorInfo securityTransparentAttributeConstructor = typeof(SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes);
76 // Mark assembly with [SecurityRules(SecurityRuleSet.Level1)]. In memory, the assembly will inherit
77 // this automatically from SDE, but when persisted it needs this attribute to be considered Level1.
78 ConstructorInfo securityRulesAttributeConstructor = typeof(SecurityRulesAttribute).GetConstructor(new Type[] { typeof(SecurityRuleSet) });
80 CustomAttributeBuilder[] attributeBuilders = new CustomAttributeBuilder[] {
81 new CustomAttributeBuilder(securityTransparentAttributeConstructor, new object[0]),
82 new CustomAttributeBuilder(securityRulesAttributeConstructor, new object[1] { SecurityRuleSet.Level1 })
85 AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, s_ProxyAssemblyBuilderAccess, attributeBuilders);
87 if (s_ProxyAssemblyBuilderAccess == AssemblyBuilderAccess.RunAndSave)
89 // Make the module persistable if the AssemblyBuilderAccess is changed to be RunAndSave.
90 moduleBuilder = assemblyBuilder.DefineDynamicModule("EntityProxyModule", "EntityProxyModule.dll");
94 moduleBuilder = assemblyBuilder.DefineDynamicModule("EntityProxyModule");
97 s_ModuleBuilders.Add(assembly, moduleBuilder);
102 internal static bool TryGetProxyType(Type clrType, string entityTypeName, out EntityProxyTypeInfo proxyTypeInfo)
104 s_TypeMapLock.EnterReadLock();
107 return s_ProxyNameMap.TryGetValue(new Tuple<Type, string>(clrType, entityTypeName), out proxyTypeInfo);
111 s_TypeMapLock.ExitReadLock();
115 internal static bool TryGetProxyType(Type proxyType, out EntityProxyTypeInfo proxyTypeInfo)
117 s_TypeMapLock.EnterReadLock();
120 return s_ProxyTypeMap.TryGetValue(proxyType, out proxyTypeInfo);
124 s_TypeMapLock.ExitReadLock();
128 internal static bool TryGetProxyWrapper(object instance, out IEntityWrapper wrapper)
130 Debug.Assert(instance != null, "the instance should not be null");
132 EntityProxyTypeInfo proxyTypeInfo;
133 if (IsProxyType(instance.GetType()) &&
134 TryGetProxyType(instance.GetType(), out proxyTypeInfo))
136 wrapper = proxyTypeInfo.GetEntityWrapper(instance);
138 return wrapper != null;
142 /// Return proxy type information for the specified O-Space EntityType.
144 /// <param name="ospaceEntityType">
145 /// EntityType in O-Space that represents the CLR type to be proxied.
146 /// Must not be null.
149 /// A non-null EntityProxyTypeInfo instance that contains information about the type of proxy for
150 /// the specified O-Space EntityType; or null if no proxy can be created for the specified type.
152 internal static EntityProxyTypeInfo GetProxyType(ClrEntityType ospaceEntityType)
154 Debug.Assert(ospaceEntityType != null, "ospaceEntityType must be non-null");
155 Debug.Assert(ospaceEntityType.DataSpace == DataSpace.OSpace, "ospaceEntityType.DataSpace must be OSpace");
157 EntityProxyTypeInfo proxyTypeInfo = null;
159 // Check if an entry for the proxy type already exists.
160 if (TryGetProxyType(ospaceEntityType.ClrType, ospaceEntityType.CSpaceTypeName, out proxyTypeInfo))
162 if (proxyTypeInfo != null)
164 proxyTypeInfo.ValidateType(ospaceEntityType);
166 return proxyTypeInfo;
169 // No entry found, may need to create one.
170 // Acquire an upgradeable read lock so that:
171 // 1. Other readers aren't blocked while the second existence check is performed.
172 // 2. Other threads that may have also detected the absence of an entry block while the first thread handles proxy type creation.
174 s_TypeMapLock.EnterUpgradeableReadLock();
177 return TryCreateProxyType(ospaceEntityType);
181 s_TypeMapLock.ExitUpgradeableReadLock();
186 /// A mechanism to lookup AssociationType metadata for proxies for a given entity and association information
188 /// <param name="wrappedEntity">The entity instance used to lookup the proxy type</param>
189 /// <param name="relationshipName">The name of the relationship (FullName or Name)</param>
190 /// <param name="targetRoleName">Target role of the relationship</param>
191 /// <param name="associationType">The AssociationType for that property</param>
192 /// <returns>True if an AssociationType is found in proxy metadata, false otherwise</returns>
193 internal static bool TryGetAssociationTypeFromProxyInfo(IEntityWrapper wrappedEntity, string relationshipName, string targetRoleName, out AssociationType associationType)
195 EntityProxyTypeInfo proxyInfo = null;
196 associationType = null;
197 return (EntityProxyFactory.TryGetProxyType(wrappedEntity.Entity.GetType(), out proxyInfo) && proxyInfo != null &&
198 proxyInfo.TryGetNavigationPropertyAssociationType(relationshipName, targetRoleName, out associationType));
202 /// Enumerate list of supplied O-Space EntityTypes,
203 /// and generate a proxy type for each EntityType (if possible for the particular type).
205 /// <param name="ospaceEntityType">
206 /// Enumeration of O-Space EntityType objects.
207 /// Must not be null.
208 /// In addition, the elements of the enumeration must not be null.
210 internal static void TryCreateProxyTypes(IEnumerable<EntityType> ospaceEntityTypes)
212 Debug.Assert(ospaceEntityTypes != null, "ospaceEntityTypes must be non-null");
214 // Acquire an upgradeable read lock for the duration of the enumeration so that:
215 // 1. Other readers aren't blocked while existence checks are performed.
216 // 2. Other threads that may have detected the absence of an entry block while the first thread handles proxy type creation.
218 s_TypeMapLock.EnterUpgradeableReadLock();
221 foreach (EntityType ospaceEntityType in ospaceEntityTypes)
223 Debug.Assert(ospaceEntityType != null, "Null EntityType element reference present in enumeration.");
224 TryCreateProxyType(ospaceEntityType);
229 s_TypeMapLock.ExitUpgradeableReadLock();
233 private static EntityProxyTypeInfo TryCreateProxyType(EntityType ospaceEntityType)
235 Debug.Assert(s_TypeMapLock.IsUpgradeableReadLockHeld, "EntityProxyTypeInfo.TryCreateProxyType method was called without first acquiring an upgradeable read lock from s_TypeMapLock.");
237 EntityProxyTypeInfo proxyTypeInfo;
238 ClrEntityType clrEntityType = (ClrEntityType)ospaceEntityType;
240 Tuple<Type, string> proxyIdentiy = new Tuple<Type, string>(clrEntityType.ClrType, clrEntityType.HashedDescription);
242 if (!s_ProxyNameMap.TryGetValue(proxyIdentiy, out proxyTypeInfo) && CanProxyType(ospaceEntityType))
244 ModuleBuilder moduleBuilder = GetDynamicModule(ospaceEntityType);
245 proxyTypeInfo = BuildType(moduleBuilder, clrEntityType);
247 s_TypeMapLock.EnterWriteLock();
250 s_ProxyNameMap[proxyIdentiy] = proxyTypeInfo;
251 if (proxyTypeInfo != null)
253 // If there is a proxy type, create the reverse lookup
254 s_ProxyTypeMap[proxyTypeInfo.ProxyType] = proxyTypeInfo;
259 s_TypeMapLock.ExitWriteLock();
263 return proxyTypeInfo;
267 /// Determine if the specified type represents a known proxy type.
269 /// <param name="type">
270 /// The Type to be examined.
273 /// True if the type is a known proxy type; otherwise false.
275 internal static bool IsProxyType(Type type)
277 Debug.Assert(type != null, "type is null, was this intended?");
278 return type != null && ProxyRuntimeAssemblies.Contains(type.Assembly);
282 /// Return an enumerable of the current set of CLR proxy types.
285 /// Enumerable of the current set of CLR proxy types.
286 /// This value will never be null.
289 /// The enumerable is based on a shapshot of the current list of types.
291 internal static IEnumerable<Type> GetKnownProxyTypes()
293 s_TypeMapLock.EnterReadLock();
296 var proxyTypes = from info in s_ProxyNameMap.Values
298 select info.ProxyType;
299 return proxyTypes.ToArray();
303 s_TypeMapLock.ExitReadLock();
307 public Func<object, object> CreateBaseGetter(Type declaringType, PropertyInfo propertyInfo)
309 Debug.Assert(propertyInfo != null, "Null propertyInfo");
311 ParameterExpression Object_Parameter = Expression.Parameter(typeof(object), "instance");
312 Func<object, object> nonProxyGetter = Expression.Lambda<Func<object, object>>(
313 Expression.PropertyOrField(
314 Expression.Convert(Object_Parameter, declaringType),
316 Object_Parameter).Compile();
318 string propertyName = propertyInfo.Name;
321 Type type = entity.GetType();
322 if (IsProxyType(type))
325 if (TryGetBasePropertyValue(type, propertyName, entity, out value))
330 return nonProxyGetter(entity);
334 private static bool TryGetBasePropertyValue(Type proxyType, string propertyName, object entity, out object value)
336 EntityProxyTypeInfo typeInfo;
338 if (TryGetProxyType(proxyType, out typeInfo) && typeInfo.ContainsBaseGetter(propertyName))
340 value = typeInfo.BaseGetter(entity, propertyName);
346 public Action<object, object> CreateBaseSetter(Type declaringType, PropertyInfo propertyInfo)
348 Debug.Assert(propertyInfo != null, "Null propertyInfo");
350 Action<object, object> nonProxySetter = LightweightCodeGenerator.CreateNavigationPropertySetter(declaringType, propertyInfo);
352 string propertyName = propertyInfo.Name;
353 return (entity, value) =>
355 Type type = entity.GetType();
356 if (IsProxyType(type))
358 if (TrySetBasePropertyValue(type, propertyName, entity, value))
363 nonProxySetter(entity, value);
367 private static bool TrySetBasePropertyValue(Type proxyType, string propertyName, object entity, object value)
369 EntityProxyTypeInfo typeInfo;
370 if (TryGetProxyType(proxyType, out typeInfo) && typeInfo.ContainsBaseSetter(propertyName))
372 typeInfo.BaseSetter(entity, propertyName, value);
379 /// Build a CLR proxy type for the supplied EntityType.
381 /// <param name="ospaceEntityType">
382 /// EntityType in O-Space that represents the CLR type to be proxied.
385 /// EntityProxyTypeInfo object that contains the constructed proxy type,
386 /// along with any behaviors associated with that type;
387 /// or null if a proxy type cannot be constructed for the specified EntityType.
389 private static EntityProxyTypeInfo BuildType(ModuleBuilder moduleBuilder, ClrEntityType ospaceEntityType)
391 Debug.Assert(s_TypeMapLock.IsUpgradeableReadLockHeld, "EntityProxyTypeInfo.BuildType method was called without first acquiring an upgradeable read lock from s_TypeMapLock.");
393 EntityProxyTypeInfo proxyTypeInfo;
395 ProxyTypeBuilder proxyTypeBuilder = new ProxyTypeBuilder(ospaceEntityType);
396 Type proxyType = proxyTypeBuilder.CreateType(moduleBuilder);
398 if (proxyType != null)
400 // Set the runtime assembly of the proxy types if it hasn't already been set.
401 // This is used by the IsProxyType method.
402 Assembly typeAssembly = proxyType.Assembly;
403 if (!ProxyRuntimeAssemblies.Contains(typeAssembly))
405 ProxyRuntimeAssemblies.Add(typeAssembly);
406 AddAssemblyToResolveList(typeAssembly);
409 proxyTypeInfo = new EntityProxyTypeInfo(proxyType, ospaceEntityType,
410 proxyTypeBuilder.CreateInitalizeCollectionMethod(proxyType),
411 proxyTypeBuilder.BaseGetters, proxyTypeBuilder.BaseSetters);
413 foreach (EdmMember member in proxyTypeBuilder.LazyLoadMembers)
415 InterceptMember(member, proxyType, proxyTypeInfo);
418 SetResetFKSetterFlagDelegate(proxyType, proxyTypeInfo);
419 SetCompareByteArraysDelegate(proxyType, proxyTypeInfo);
423 proxyTypeInfo = null;
426 return proxyTypeInfo;
430 /// In order for deserialization of proxy objects to succeed in this AppDomain,
431 /// an assembly resolve handler must be added to the AppDomain to resolve the dynamic assembly,
432 /// since it is not present in a location discoverable by fusion.
434 /// <param name="assembly">Proxy assembly to be resolved.</param>
435 [SecuritySafeCritical]
436 private static void AddAssemblyToResolveList(Assembly assembly)
438 if (ProxyRuntimeAssemblies.Contains(assembly)) // If the assembly is not a known proxy assembly, ignore it.
440 ResolveEventHandler resolveHandler = new ResolveEventHandler((sender, args) => args.Name == assembly.FullName ? assembly : null);
441 AppDomain.CurrentDomain.AssemblyResolve += resolveHandler;
446 /// Construct an interception delegate for the specified proxy member.
448 /// <param name="member">
449 /// EdmMember that specifies the member to be intercepted.
451 /// <param name="proxyType">
452 /// Type of the proxy.
454 /// <param name="lazyLoadBehavior">
455 /// LazyLoadBehavior object that supplies the behavior to load related ends.
457 [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
458 private static void InterceptMember(EdmMember member, Type proxyType, EntityProxyTypeInfo proxyTypeInfo)
460 PropertyInfo property = EntityUtil.GetTopProperty(proxyType, member.Name);
461 Debug.Assert(property != null, String.Format(CultureInfo.CurrentCulture, "Expected property {0} to be defined on proxy type {1}", member.Name, proxyType.FullName));
463 FieldInfo interceptorField = proxyType.GetField(LazyLoadImplementor.GetInterceptorFieldName(member.Name), BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic);
464 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));
466 Delegate interceptorDelegate = typeof(LazyLoadBehavior).GetMethod("GetInterceptorDelegate", BindingFlags.NonPublic | BindingFlags.Static).
467 MakeGenericMethod(proxyType, property.PropertyType).
468 Invoke(null, new object[] { member, proxyTypeInfo.EntityWrapperDelegate }) as Delegate;
470 AssignInterceptionDelegate(interceptorDelegate, interceptorField);
474 /// Set the interceptor on a proxy member.
476 /// <param name="interceptorDelegate">
477 /// Delegate to be set
479 /// <param name="interceptorField">
480 /// Field define on the proxy type to store the reference to the interception delegate.
482 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2128")]
483 [SecuritySafeCritical]
484 [ReflectionPermission(SecurityAction.Assert, MemberAccess = true)]
485 [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
486 private static void AssignInterceptionDelegate(Delegate interceptorDelegate, FieldInfo interceptorField)
488 interceptorField.SetValue(null, interceptorDelegate);
492 /// Sets a delegate onto the _resetFKSetterFlag field such that it can be executed to make
493 /// a call into the state manager to reset the InFKSetter flag.
495 private static void SetResetFKSetterFlagDelegate(Type proxyType, EntityProxyTypeInfo proxyTypeInfo)
497 var resetFKSetterFlagField = proxyType.GetField(ResetFKSetterFlagFieldName, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic);
498 Debug.Assert(resetFKSetterFlagField != null, "Expected resetFKSetterFlagField to be defined on the proxy type.");
500 var resetFKSetterFlagDelegate = GetResetFKSetterFlagDelegate(proxyTypeInfo.EntityWrapperDelegate);
502 AssignInterceptionDelegate(resetFKSetterFlagDelegate, resetFKSetterFlagField);
506 /// Returns the delegate that takes a proxy instance and uses it to reset the InFKSetter flag maintained
507 /// by the state manager of the context associated with the proxy instance.
509 private static Action<object> GetResetFKSetterFlagDelegate(Func<object, object> getEntityWrapperDelegate)
513 Debug.Assert(getEntityWrapperDelegate != null, "entityWrapperDelegate must not be null");
515 ResetFKSetterFlag(getEntityWrapperDelegate(proxy));
520 /// Called in the finally clause of each overridden property setter to ensure that the flag
521 /// indicating that we are in an FK setter is cleared. Note that the wrapped entity is passed as
522 /// an obejct becayse IEntityWrapper is an internal type and is therefore not accessable to
523 /// the proxy type. Once we're in the framework it is cast back to an IEntityWrapper.
525 private static void ResetFKSetterFlag(object wrappedEntityAsObject)
527 Debug.Assert(wrappedEntityAsObject == null || wrappedEntityAsObject is IEntityWrapper, "wrappedEntityAsObject must be an IEntityWrapper");
528 var wrappedEntity = (IEntityWrapper)wrappedEntityAsObject; // We want an exception if the cast fails.
529 if (wrappedEntity != null && wrappedEntity.Context != null)
531 wrappedEntity.Context.ObjectStateManager.EntityInvokingFKSetter = null;
536 /// Sets a delegate onto the _compareByteArrays field such that it can be executed to check
537 /// whether two byte arrays are the same by value comparison.
539 private static void SetCompareByteArraysDelegate(Type proxyType, EntityProxyTypeInfo proxyTypeInfo)
541 var compareByteArraysField = proxyType.GetField(CompareByteArraysFieldName, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.NonPublic);
542 Debug.Assert(compareByteArraysField != null, "Expected compareByteArraysField to be defined on the proxy type.");
544 AssignInterceptionDelegate(new Func<object, object, bool>(ByValueEqualityComparer.Default.Equals), compareByteArraysField);
548 /// Return boolean that specifies if the specified type can be proxied.
550 /// <param name="ospaceEntityType">O-space EntityType</param>
552 /// True if the class is not abstract or sealed, does not implement IEntityWithRelationships,
553 /// and has a public or protected default constructor; otherwise false.
556 /// While it is technically possible to derive from an abstract type
557 /// in order to create a proxy, we avoid this so that the proxy type
558 /// has the same "concreteness" of the type being proxied.
559 /// The check for IEntityWithRelationships ensures that codegen'ed
560 /// entities that derive from EntityObject as well as properly
561 /// constructed IPOCO entities will not be proxied.
564 private static bool CanProxyType(EntityType ospaceEntityType)
566 TypeAttributes access = ospaceEntityType.ClrType.Attributes & TypeAttributes.VisibilityMask;
568 ConstructorInfo ctor = ospaceEntityType.ClrType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, Type.EmptyTypes, null);
569 bool accessableCtor = ctor != null && (((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) ||
570 ((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family) ||
571 ((ctor.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem));
573 return (!(ospaceEntityType.Abstract ||
574 ospaceEntityType.ClrType.IsSealed ||
575 typeof(IEntityWithRelationships).IsAssignableFrom(ospaceEntityType.ClrType) ||
577 access == TypeAttributes.Public);
580 private static bool CanProxyMethod(MethodInfo method)
586 MethodAttributes access = method.Attributes & MethodAttributes.MemberAccessMask;
587 result = method.IsVirtual &&
589 (access == MethodAttributes.Public ||
590 access == MethodAttributes.Family ||
591 access == MethodAttributes.FamORAssem);
597 internal static bool CanProxyGetter(PropertyInfo clrProperty)
599 Debug.Assert(clrProperty != null, "clrProperty should have a value");
600 return CanProxyMethod(clrProperty.GetGetMethod(true));
603 internal static bool CanProxySetter(PropertyInfo clrProperty)
605 Debug.Assert(clrProperty != null, "clrProperty should have a value");
606 return CanProxyMethod(clrProperty.GetSetMethod(true));
609 private class ProxyTypeBuilder
611 private TypeBuilder _typeBuilder;
612 private BaseProxyImplementor _baseImplementor;
613 private IPOCOImplementor _ipocoImplementor;
614 private LazyLoadImplementor _lazyLoadImplementor;
615 private DataContractImplementor _dataContractImplementor;
616 private ISerializableImplementor _iserializableImplementor;
617 private ClrEntityType _ospaceEntityType;
618 private ModuleBuilder _moduleBuilder;
619 private List<FieldBuilder> _serializedFields = new List<FieldBuilder>(3);
621 public ProxyTypeBuilder(ClrEntityType ospaceEntityType)
623 _ospaceEntityType = ospaceEntityType;
624 _baseImplementor = new BaseProxyImplementor();
625 _ipocoImplementor = new IPOCOImplementor(ospaceEntityType);
626 _lazyLoadImplementor = new LazyLoadImplementor(ospaceEntityType);
627 _dataContractImplementor = new DataContractImplementor(ospaceEntityType);
628 _iserializableImplementor = new ISerializableImplementor(ospaceEntityType);
633 get { return _ospaceEntityType.ClrType; }
636 public DynamicMethod CreateInitalizeCollectionMethod(Type proxyType)
638 return _ipocoImplementor.CreateInitalizeCollectionMethod(proxyType);
641 public List<PropertyInfo> BaseGetters
645 return _baseImplementor.BaseGetters;
649 public List<PropertyInfo> BaseSetters
653 return _baseImplementor.BaseSetters;
657 public IEnumerable<EdmMember> LazyLoadMembers
659 get { return _lazyLoadImplementor.Members; }
662 public Type CreateType(ModuleBuilder moduleBuilder)
664 _moduleBuilder = moduleBuilder;
665 bool hadProxyProperties = false;
667 if (_iserializableImplementor.TypeIsSuitable)
669 foreach (EdmMember member in _ospaceEntityType.Members)
671 if (_ipocoImplementor.CanProxyMember(member) ||
672 _lazyLoadImplementor.CanProxyMember(member))
674 PropertyInfo baseProperty = EntityUtil.GetTopProperty(BaseType, member.Name);
675 PropertyBuilder propertyBuilder = TypeBuilder.DefineProperty(member.Name, System.Reflection.PropertyAttributes.None, baseProperty.PropertyType, Type.EmptyTypes);
677 if (!_ipocoImplementor.EmitMember(TypeBuilder, member, propertyBuilder, baseProperty, _baseImplementor))
679 EmitBaseSetter(TypeBuilder, propertyBuilder, baseProperty);
681 if (!_lazyLoadImplementor.EmitMember(TypeBuilder, member, propertyBuilder, baseProperty, _baseImplementor))
683 EmitBaseGetter(TypeBuilder, propertyBuilder, baseProperty);
686 hadProxyProperties = true;
690 if (_typeBuilder != null)
692 _baseImplementor.Implement(TypeBuilder, RegisterInstanceField);
693 _iserializableImplementor.Implement(TypeBuilder, _serializedFields);
697 return hadProxyProperties ? TypeBuilder.CreateType() : null;
700 private TypeBuilder TypeBuilder
704 if (_typeBuilder == null)
706 TypeAttributes proxyTypeAttributes = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
707 if ((BaseType.Attributes & TypeAttributes.Serializable) == TypeAttributes.Serializable)
709 proxyTypeAttributes |= TypeAttributes.Serializable;
712 // If the type as a long name, then use only the first part of it so that there is no chance that the generated
713 // name will be too long. Note that the full name always gets used to compute the hash.
714 string baseName = BaseType.Name.Length <= 20 ? BaseType.Name : BaseType.Name.Substring(0, 20);
715 string proxyTypeName = String.Format(CultureInfo.InvariantCulture, ProxyTypeNameFormat, baseName, _ospaceEntityType.HashedDescription);
717 _typeBuilder = _moduleBuilder.DefineType(proxyTypeName, proxyTypeAttributes, BaseType, _ipocoImplementor.Interfaces);
718 _typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName);
720 Action<FieldBuilder, bool> registerField = RegisterInstanceField;
721 _ipocoImplementor.Implement(_typeBuilder, registerField);
722 _lazyLoadImplementor.Implement(_typeBuilder, registerField);
724 // WCF data contract serialization is not compatible with types that implement ISerializable.
725 if (!_iserializableImplementor.TypeImplementsISerializable)
727 _dataContractImplementor.Implement(_typeBuilder, registerField);
734 private void EmitBaseGetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty)
736 if (CanProxyGetter(baseProperty))
738 MethodInfo baseGetter = baseProperty.GetGetMethod(true);
739 const MethodAttributes getterAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
740 MethodAttributes getterAccess = baseGetter.Attributes & MethodAttributes.MemberAccessMask;
742 // Define a property getter override in the proxy type
743 MethodBuilder getterBuilder = typeBuilder.DefineMethod("get_" + baseProperty.Name, getterAccess | getterAttributes, baseProperty.PropertyType, Type.EmptyTypes);
744 ILGenerator gen = getterBuilder.GetILGenerator();
746 gen.Emit(OpCodes.Ldarg_0);
747 gen.Emit(OpCodes.Call, baseGetter);
748 gen.Emit(OpCodes.Ret);
750 propertyBuilder.SetGetMethod(getterBuilder);
754 private void EmitBaseSetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty)
756 if (CanProxySetter(baseProperty))
759 MethodInfo baseSetter = baseProperty.GetSetMethod(true); ;
760 const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
761 MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask;
763 MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType });
764 ILGenerator generator = setterBuilder.GetILGenerator();
765 generator.Emit(OpCodes.Ldarg_0);
766 generator.Emit(OpCodes.Ldarg_1);
767 generator.Emit(OpCodes.Call, baseSetter);
768 generator.Emit(OpCodes.Ret);
769 propertyBuilder.SetSetMethod(setterBuilder);
773 private void RegisterInstanceField(FieldBuilder field, bool serializable)
777 _serializedFields.Add(field);
781 MarkAsNotSerializable(field);
785 private static readonly ConstructorInfo s_NonSerializedAttributeConstructor = typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes);
786 private static readonly ConstructorInfo s_IgnoreDataMemberAttributeConstructor = typeof(IgnoreDataMemberAttribute).GetConstructor(Type.EmptyTypes);
787 private static readonly ConstructorInfo s_XmlIgnoreAttributeConstructor = typeof(System.Xml.Serialization.XmlIgnoreAttribute).GetConstructor(Type.EmptyTypes);
788 private static readonly ConstructorInfo s_ScriptIgnoreAttributeConstructor = TryGetScriptIgnoreAttributeType().GetConstructor(Type.EmptyTypes);
790 private static Type TryGetScriptIgnoreAttributeType()
794 var scriptIgnoreAttributeAssembly = Assembly.Load(AssemblyRef.SystemWebExtensions);
795 return scriptIgnoreAttributeAssembly.GetType(@"System.Web.Script.Serialization.ScriptIgnoreAttribute");
800 // We should not assert in EF6, at least when produce a build compatible with .NET 4.0 client SKU
801 Debug.Assert(false, "Unable to find ScriptIgnoreAttribute type");
805 private static void MarkAsNotSerializable(FieldBuilder field)
807 object[] emptyArray = new object[0];
809 field.SetCustomAttribute(new CustomAttributeBuilder(s_NonSerializedAttributeConstructor, emptyArray));
813 field.SetCustomAttribute(new CustomAttributeBuilder(s_IgnoreDataMemberAttributeConstructor, emptyArray));
814 field.SetCustomAttribute(new CustomAttributeBuilder(s_XmlIgnoreAttributeConstructor, emptyArray));
816 if (s_ScriptIgnoreAttributeConstructor != null)
818 field.SetCustomAttribute(new CustomAttributeBuilder(s_ScriptIgnoreAttributeConstructor, emptyArray));
825 internal class LazyLoadImplementor
827 HashSet<EdmMember> _members;
829 public LazyLoadImplementor(EntityType ospaceEntityType)
831 CheckType(ospaceEntityType);
834 public IEnumerable<EdmMember> Members
836 get { return _members; }
839 private void CheckType(EntityType ospaceEntityType)
841 _members = new HashSet<EdmMember>();
843 foreach (EdmMember member in ospaceEntityType.Members)
845 PropertyInfo clrProperty = EntityUtil.GetTopProperty(ospaceEntityType.ClrType, member.Name);
846 if (clrProperty != null &&
847 EntityProxyFactory.CanProxyGetter(clrProperty) &&
848 LazyLoadBehavior.IsLazyLoadCandidate(ospaceEntityType, member))
850 _members.Add(member);
855 public bool CanProxyMember(EdmMember member)
857 return _members.Contains(member);
860 public void Implement(TypeBuilder typeBuilder, Action<FieldBuilder, bool> registerField)
862 // Add instance field to store IEntityWrapper instance
863 // The field is typed as object, for two reasons:
864 // 1. The practical one, IEntityWrapper is internal and not accessible from the dynamic assembly.
865 // 2. We purposely want the wrapper field to be opaque on the proxy type.
866 FieldBuilder wrapperField = typeBuilder.DefineField(EntityProxyTypeInfo.EntityWrapperFieldName, typeof(object), FieldAttributes.Public);
867 registerField(wrapperField, false);
870 public bool EmitMember(TypeBuilder typeBuilder, EdmMember member, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, BaseProxyImplementor baseImplementor)
872 if (_members.Contains(member))
874 MethodInfo baseGetter = baseProperty.GetGetMethod(true);
875 const MethodAttributes getterAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
876 MethodAttributes getterAccess = baseGetter.Attributes & MethodAttributes.MemberAccessMask;
878 // Define field to store interceptor Func
879 // Signature of interceptor Func delegate is as follows:
881 // bool intercept(ProxyType proxy, PropertyType propertyValue)
884 // PropertyType is the type of the Property, such as ICollection<Customer>,
885 // ProxyType is the type of the proxy object,
886 // propertyValue is the value returned from the proxied type's property getter.
888 Type interceptorType = typeof(Func<,,>).MakeGenericType(typeBuilder, baseProperty.PropertyType, typeof(bool));
889 MethodInfo interceptorInvoke = TypeBuilder.GetMethod(interceptorType, typeof(Func<,,>).GetMethod("Invoke"));
890 FieldBuilder interceptorField = typeBuilder.DefineField(GetInterceptorFieldName(baseProperty.Name), interceptorType, FieldAttributes.Private | FieldAttributes.Static);
892 // Define a property getter override in the proxy type
893 MethodBuilder getterBuilder = typeBuilder.DefineMethod("get_" + baseProperty.Name, getterAccess | getterAttributes, baseProperty.PropertyType, Type.EmptyTypes);
894 ILGenerator generator = getterBuilder.GetILGenerator();
896 // Emit instructions for the following call:
897 // T value = base.SomeProperty;
898 // if(this._interceptorForSomeProperty(this, value))
900 // return base.SomeProperty;
901 // where _interceptorForSomeProperty represents the interceptor Func field.
903 Label lableTrue = generator.DefineLabel();
904 generator.DeclareLocal(baseProperty.PropertyType); // T value
905 generator.Emit(OpCodes.Ldarg_0); // call base.SomeProperty
906 generator.Emit(OpCodes.Call, baseGetter); // call to base property getter
907 generator.Emit(OpCodes.Stloc_0); // value = result
908 generator.Emit(OpCodes.Ldarg_0); // load this
909 generator.Emit(OpCodes.Ldfld, interceptorField); // load this._interceptor
910 generator.Emit(OpCodes.Ldarg_0); // load this
911 generator.Emit(OpCodes.Ldloc_0); // load value
912 generator.Emit(OpCodes.Callvirt, interceptorInvoke); // call to interceptor delegate with (this, value)
913 generator.Emit(OpCodes.Brtrue_S, lableTrue); // if true, just return
914 generator.Emit(OpCodes.Ldarg_0); // else, call the base propertty getter again
915 generator.Emit(OpCodes.Call, baseGetter); // call to base property getter
916 generator.Emit(OpCodes.Ret);
917 generator.MarkLabel(lableTrue);
918 generator.Emit(OpCodes.Ldloc_0);
919 generator.Emit(OpCodes.Ret);
921 propertyBuilder.SetGetMethod(getterBuilder);
923 baseImplementor.AddBasePropertyGetter(baseProperty);
930 internal static string GetInterceptorFieldName(string memberName)
932 return "ef_proxy_interceptorFor" + memberName;
937 internal class BaseProxyImplementor
939 private readonly List<PropertyInfo> _baseGetters;
940 private readonly List<PropertyInfo> _baseSetters;
942 public BaseProxyImplementor()
944 _baseGetters = new List<PropertyInfo>();
945 _baseSetters = new List<PropertyInfo>();
948 public List<PropertyInfo> BaseGetters
950 get { return _baseGetters; }
953 public List<PropertyInfo> BaseSetters
955 get { return _baseSetters; }
957 public void AddBasePropertyGetter(PropertyInfo baseProperty)
959 _baseGetters.Add(baseProperty);
962 public void AddBasePropertySetter(PropertyInfo baseProperty)
964 _baseSetters.Add(baseProperty);
967 public void Implement(TypeBuilder typeBuilder, Action<FieldBuilder, bool> registerField)
969 if (_baseGetters.Count > 0)
971 ImplementBaseGetter(typeBuilder);
973 if (_baseSetters.Count > 0)
975 ImplementBaseSetter(typeBuilder);
979 static readonly MethodInfo s_StringEquals = typeof(string).GetMethod("op_Equality", new Type[] { typeof(string), typeof(string) });
980 static readonly ConstructorInfo s_InvalidOperationConstructor = typeof(InvalidOperationException).GetConstructor(Type.EmptyTypes);
982 private void ImplementBaseGetter(TypeBuilder typeBuilder)
984 // Define a property getter in the proxy type
985 MethodBuilder getterBuilder = typeBuilder.DefineMethod("GetBasePropertyValue", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(object), new Type[] { typeof(string) });
986 ILGenerator gen = getterBuilder.GetILGenerator();
987 Label[] labels = new Label[_baseGetters.Count];
989 for (int i = 0; i < _baseGetters.Count; i++)
991 labels[i] = gen.DefineLabel();
992 gen.Emit(OpCodes.Ldarg_1);
993 gen.Emit(OpCodes.Ldstr, _baseGetters[i].Name);
994 gen.Emit(OpCodes.Call, s_StringEquals);
995 gen.Emit(OpCodes.Brfalse_S, labels[i]);
996 gen.Emit(OpCodes.Ldarg_0);
997 gen.Emit(OpCodes.Call, _baseGetters[i].GetGetMethod(true));
998 gen.Emit(OpCodes.Ret);
999 gen.MarkLabel(labels[i]);
1001 gen.Emit(OpCodes.Newobj, s_InvalidOperationConstructor);
1002 gen.Emit(OpCodes.Throw);
1005 private void ImplementBaseSetter(TypeBuilder typeBuilder)
1007 MethodBuilder setterBuilder = typeBuilder.DefineMethod("SetBasePropertyValue", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(string), typeof(object) });
1008 ILGenerator gen = setterBuilder.GetILGenerator();
1010 Label[] labels = new Label[_baseSetters.Count];
1012 for (int i = 0; i < _baseSetters.Count; i++)
1014 labels[i] = gen.DefineLabel();
1015 gen.Emit(OpCodes.Ldarg_1);
1016 gen.Emit(OpCodes.Ldstr, _baseSetters[i].Name);
1017 gen.Emit(OpCodes.Call, s_StringEquals);
1018 gen.Emit(OpCodes.Brfalse_S, labels[i]);
1019 gen.Emit(OpCodes.Ldarg_0);
1020 gen.Emit(OpCodes.Ldarg_2);
1021 gen.Emit(OpCodes.Castclass, _baseSetters[i].PropertyType);
1022 gen.Emit(OpCodes.Call, _baseSetters[i].GetSetMethod(true));
1023 gen.Emit(OpCodes.Ret);
1024 gen.MarkLabel(labels[i]);
1026 gen.Emit(OpCodes.Newobj, s_InvalidOperationConstructor);
1027 gen.Emit(OpCodes.Throw);
1031 internal class IPOCOImplementor
1033 private EntityType _ospaceEntityType;
1035 FieldBuilder _changeTrackerField;
1036 FieldBuilder _relationshipManagerField;
1037 FieldBuilder _resetFKSetterFlagField;
1038 FieldBuilder _compareByteArraysField;
1040 MethodBuilder _entityMemberChanging;
1041 MethodBuilder _entityMemberChanged;
1042 MethodBuilder _getRelationshipManager;
1044 private List<KeyValuePair<NavigationProperty, PropertyInfo>> _referenceProperties;
1045 private List<KeyValuePair<NavigationProperty, PropertyInfo>> _collectionProperties;
1046 private bool _implementIEntityWithChangeTracker;
1047 private bool _implementIEntityWithRelationships;
1048 private HashSet<EdmMember> _scalarMembers;
1049 private HashSet<EdmMember> _relationshipMembers;
1051 static readonly MethodInfo s_EntityMemberChanging = typeof(IEntityChangeTracker).GetMethod("EntityMemberChanging", new Type[] { typeof(string) });
1052 static readonly MethodInfo s_EntityMemberChanged = typeof(IEntityChangeTracker).GetMethod("EntityMemberChanged", new Type[] { typeof(string) });
1053 static readonly MethodInfo s_CreateRelationshipManager = typeof(RelationshipManager).GetMethod("Create", new Type[] { typeof(IEntityWithRelationships) });
1054 static readonly MethodInfo s_GetRelationshipManager = typeof(IEntityWithRelationships).GetProperty("RelationshipManager").GetGetMethod();
1055 static readonly MethodInfo s_GetRelatedReference = typeof(RelationshipManager).GetMethod("GetRelatedReference", new Type[] { typeof(string), typeof(string) });
1056 static readonly MethodInfo s_GetRelatedCollection = typeof(RelationshipManager).GetMethod("GetRelatedCollection", new Type[] { typeof(string), typeof(string) });
1057 static readonly MethodInfo s_GetRelatedEnd = typeof(RelationshipManager).GetMethod("GetRelatedEnd", new Type[] { typeof(string), typeof(string) });
1058 static readonly MethodInfo s_ObjectEquals = typeof(object).GetMethod("Equals", new Type[] { typeof(object), typeof(object) });
1059 static readonly ConstructorInfo s_InvalidOperationConstructor = typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) });
1060 static readonly MethodInfo s_IEntityWrapper_GetEntity = typeof(IEntityWrapper).GetProperty("Entity").GetGetMethod();
1061 static readonly MethodInfo s_Action_Invoke = typeof(Action<object>).GetMethod("Invoke", new Type[] { typeof(object) });
1062 static readonly MethodInfo s_Func_object_object_bool_Invoke = typeof(Func<object, object, bool>).GetMethod("Invoke", new Type[] { typeof(object), typeof(object) });
1064 private static readonly ConstructorInfo s_BrowsableAttributeConstructor = typeof(BrowsableAttribute).GetConstructor(new Type[] { typeof(bool) });
1066 public IPOCOImplementor(EntityType ospaceEntityType)
1068 Type baseType = ospaceEntityType.ClrType;
1069 _referenceProperties = new List<KeyValuePair<NavigationProperty, PropertyInfo>>();
1070 _collectionProperties = new List<KeyValuePair<NavigationProperty, PropertyInfo>>();
1072 _implementIEntityWithChangeTracker = (null == baseType.GetInterface(typeof(IEntityWithChangeTracker).Name));
1073 _implementIEntityWithRelationships = (null == baseType.GetInterface(typeof(IEntityWithRelationships).Name));
1075 CheckType(ospaceEntityType);
1077 _ospaceEntityType = ospaceEntityType;
1080 private void CheckType(EntityType ospaceEntityType)
1082 _scalarMembers = new HashSet<EdmMember>();
1083 _relationshipMembers = new HashSet<EdmMember>();
1085 foreach (EdmMember member in ospaceEntityType.Members)
1087 PropertyInfo clrProperty = EntityUtil.GetTopProperty(ospaceEntityType.ClrType, member.Name);
1088 if (clrProperty != null && EntityProxyFactory.CanProxySetter(clrProperty))
1090 if (member.BuiltInTypeKind == BuiltInTypeKind.EdmProperty)
1092 if (_implementIEntityWithChangeTracker)
1094 _scalarMembers.Add(member);
1097 else if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty)
1099 if (_implementIEntityWithRelationships)
1101 NavigationProperty navProperty = (NavigationProperty)member;
1102 RelationshipMultiplicity multiplicity = navProperty.ToEndMember.RelationshipMultiplicity;
1104 if (multiplicity == RelationshipMultiplicity.Many)
1106 if (clrProperty.PropertyType.IsGenericType &&
1107 clrProperty.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
1109 _relationshipMembers.Add(member);
1114 _relationshipMembers.Add(member);
1121 if (ospaceEntityType.Members.Count != _scalarMembers.Count + _relationshipMembers.Count)
1123 _scalarMembers.Clear();
1124 _relationshipMembers.Clear();
1125 _implementIEntityWithChangeTracker = false;
1126 _implementIEntityWithRelationships = false;
1130 public void Implement(TypeBuilder typeBuilder, Action<FieldBuilder, bool> registerField)
1132 if (_implementIEntityWithChangeTracker)
1134 ImplementIEntityWithChangeTracker(typeBuilder, registerField);
1136 if (_implementIEntityWithRelationships)
1138 ImplementIEntityWithRelationships(typeBuilder, registerField);
1141 _resetFKSetterFlagField = typeBuilder.DefineField(EntityProxyFactory.ResetFKSetterFlagFieldName, typeof(Action<object>), FieldAttributes.Private| FieldAttributes.Static);
1142 _compareByteArraysField = typeBuilder.DefineField(EntityProxyFactory.CompareByteArraysFieldName, typeof(Func<object, object, bool>), FieldAttributes.Private | FieldAttributes.Static);
1145 public Type[] Interfaces
1149 List<Type> types = new List<Type>();
1150 if (_implementIEntityWithChangeTracker) { types.Add(typeof(IEntityWithChangeTracker)); }
1151 if (_implementIEntityWithRelationships) { types.Add(typeof(IEntityWithRelationships)); }
1152 return types.ToArray();
1156 public DynamicMethod CreateInitalizeCollectionMethod(Type proxyType)
1158 if (_collectionProperties.Count > 0)
1160 DynamicMethod initializeEntityCollections = LightweightCodeGenerator.CreateDynamicMethod(proxyType.Name + "_InitializeEntityCollections", typeof(IEntityWrapper), new Type[] { typeof(IEntityWrapper) });
1161 ILGenerator generator = initializeEntityCollections.GetILGenerator();
1162 generator.DeclareLocal(proxyType);
1163 generator.DeclareLocal(typeof(RelationshipManager));
1164 generator.Emit(OpCodes.Ldarg_0);
1165 generator.Emit(OpCodes.Callvirt, s_IEntityWrapper_GetEntity);
1166 generator.Emit(OpCodes.Castclass, proxyType);
1167 generator.Emit(OpCodes.Stloc_0);
1168 generator.Emit(OpCodes.Ldloc_0);
1169 generator.Emit(OpCodes.Callvirt, s_GetRelationshipManager);
1170 generator.Emit(OpCodes.Stloc_1);
1172 foreach (KeyValuePair<NavigationProperty, PropertyInfo> navProperty in _collectionProperties)
1174 // Update Constructor to initialize this property
1175 MethodInfo getRelatedCollection = s_GetRelatedCollection.MakeGenericMethod(EntityUtil.GetCollectionElementType(navProperty.Value.PropertyType));
1177 generator.Emit(OpCodes.Ldloc_0);
1178 generator.Emit(OpCodes.Ldloc_1);
1179 generator.Emit(OpCodes.Ldstr, navProperty.Key.RelationshipType.FullName);
1180 generator.Emit(OpCodes.Ldstr, navProperty.Key.ToEndMember.Name);
1181 generator.Emit(OpCodes.Callvirt, getRelatedCollection);
1182 generator.Emit(OpCodes.Callvirt, navProperty.Value.GetSetMethod(true));
1184 generator.Emit(OpCodes.Ldarg_0);
1185 generator.Emit(OpCodes.Ret);
1187 return initializeEntityCollections;
1192 public bool CanProxyMember(EdmMember member)
1194 return _scalarMembers.Contains(member) || _relationshipMembers.Contains(member);
1197 public bool EmitMember(TypeBuilder typeBuilder, EdmMember member, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, BaseProxyImplementor baseImplementor)
1199 if (_scalarMembers.Contains(member))
1201 bool isKeyMember = _ospaceEntityType.KeyMembers.Contains(member.Identity);
1202 EmitScalarSetter(typeBuilder, propertyBuilder, baseProperty, isKeyMember);
1205 else if (_relationshipMembers.Contains(member))
1207 Debug.Assert(member != null, "member is null");
1208 Debug.Assert(member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty);
1209 NavigationProperty navProperty = member as NavigationProperty;
1210 if (navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
1212 EmitCollectionProperty(typeBuilder, propertyBuilder, baseProperty, navProperty);
1216 EmitReferenceProperty(typeBuilder, propertyBuilder, baseProperty, navProperty);
1218 baseImplementor.AddBasePropertySetter(baseProperty);
1224 private void EmitScalarSetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, bool isKeyMember)
1226 MethodInfo baseSetter = baseProperty.GetSetMethod(true);
1227 const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
1228 MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask;
1230 MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType });
1231 ILGenerator generator = setterBuilder.GetILGenerator();
1232 Label endOfMethod = generator.DefineLabel();
1234 // If the CLR property represents a key member of the Entity Type,
1235 // ignore attempts to set the key value to the same value.
1238 MethodInfo baseGetter = baseProperty.GetGetMethod(true);
1240 if (baseGetter != null)
1242 // if (base.[Property] != value)
1244 // // perform set operation
1247 Type propertyType = baseProperty.PropertyType;
1249 if (propertyType == typeof(int) || // signed integer types
1250 propertyType == typeof(short) ||
1251 propertyType == typeof(Int64) ||
1252 propertyType == typeof(bool) || // boolean
1253 propertyType == typeof(byte) ||
1254 propertyType == typeof(UInt32) ||
1255 propertyType == typeof(UInt64)||
1256 propertyType == typeof(float) ||
1257 propertyType == typeof(double) ||
1258 propertyType.IsEnum)
1260 generator.Emit(OpCodes.Ldarg_0);
1261 generator.Emit(OpCodes.Call, baseGetter);
1262 generator.Emit(OpCodes.Ldarg_1);
1263 generator.Emit(OpCodes.Beq_S, endOfMethod);
1265 else if (propertyType == typeof(byte[]))
1267 // Byte arrays must be compared by value
1268 generator.Emit(OpCodes.Ldsfld, _compareByteArraysField);
1269 generator.Emit(OpCodes.Ldarg_0);
1270 generator.Emit(OpCodes.Call, baseGetter);
1271 generator.Emit(OpCodes.Ldarg_1);
1272 generator.Emit(OpCodes.Callvirt, s_Func_object_object_bool_Invoke);
1273 generator.Emit(OpCodes.Brtrue_S, endOfMethod);
1277 // Get the specific type's inequality method if it exists
1278 MethodInfo op_inequality = propertyType.GetMethod("op_Inequality", new Type[] { propertyType, propertyType });
1279 if (op_inequality != null)
1281 generator.Emit(OpCodes.Ldarg_0);
1282 generator.Emit(OpCodes.Call, baseGetter);
1283 generator.Emit(OpCodes.Ldarg_1);
1284 generator.Emit(OpCodes.Call, op_inequality);
1285 generator.Emit(OpCodes.Brfalse_S, endOfMethod);
1289 // Use object inequality
1290 generator.Emit(OpCodes.Ldarg_0);
1291 generator.Emit(OpCodes.Call, baseGetter);
1292 if (propertyType.IsValueType)
1294 generator.Emit(OpCodes.Box, propertyType);
1296 generator.Emit(OpCodes.Ldarg_1);
1297 if (propertyType.IsValueType)
1299 generator.Emit(OpCodes.Box, propertyType);
1301 generator.Emit(OpCodes.Call, s_ObjectEquals);
1302 generator.Emit(OpCodes.Brtrue_S, endOfMethod);
1308 // Creates code like this:
1312 // MemberChanging(propertyName);
1313 // base.Property_set(value);
1314 // MemberChanged(propertyName);
1318 // _resetFKSetterFlagField(this);
1321 // Note that the try/finally ensures that even if an exception causes
1322 // the setting of the property to be aborted, we still clear the flag that
1323 // indicates that we are in a property setter.
1325 generator.BeginExceptionBlock();
1326 generator.Emit(OpCodes.Ldarg_0);
1327 generator.Emit(OpCodes.Ldstr, baseProperty.Name);
1328 generator.Emit(OpCodes.Call, _entityMemberChanging);
1329 generator.Emit(OpCodes.Ldarg_0);
1330 generator.Emit(OpCodes.Ldarg_1);
1331 generator.Emit(OpCodes.Call, baseSetter);
1332 generator.Emit(OpCodes.Ldarg_0);
1333 generator.Emit(OpCodes.Ldstr, baseProperty.Name);
1334 generator.Emit(OpCodes.Call, _entityMemberChanged);
1335 generator.BeginFinallyBlock();
1336 generator.Emit(OpCodes.Ldsfld, _resetFKSetterFlagField);
1337 generator.Emit(OpCodes.Ldarg_0);
1338 generator.Emit(OpCodes.Callvirt, s_Action_Invoke);
1339 generator.EndExceptionBlock();
1340 generator.MarkLabel(endOfMethod);
1341 generator.Emit(OpCodes.Ret);
1342 propertyBuilder.SetSetMethod(setterBuilder);
1345 private void EmitReferenceProperty(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, NavigationProperty navProperty)
1347 const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
1348 MethodInfo baseSetter = baseProperty.GetSetMethod(true); ;
1349 MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask;
1351 MethodInfo specificGetRelatedReference = s_GetRelatedReference.MakeGenericMethod(baseProperty.PropertyType);
1352 MethodInfo specificEntityReferenceSetValue = typeof(EntityReference<>).MakeGenericType(baseProperty.PropertyType).GetMethod("set_Value"); ;
1354 MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType });
1355 ILGenerator generator = setterBuilder.GetILGenerator();
1356 generator.Emit(OpCodes.Ldarg_0);
1357 generator.Emit(OpCodes.Callvirt, _getRelationshipManager);
1358 generator.Emit(OpCodes.Ldstr, navProperty.RelationshipType.FullName);
1359 generator.Emit(OpCodes.Ldstr, navProperty.ToEndMember.Name);
1360 generator.Emit(OpCodes.Callvirt, specificGetRelatedReference);
1361 generator.Emit(OpCodes.Ldarg_1);
1362 generator.Emit(OpCodes.Callvirt, specificEntityReferenceSetValue);
1363 generator.Emit(OpCodes.Ret);
1364 propertyBuilder.SetSetMethod(setterBuilder);
1366 _referenceProperties.Add(new KeyValuePair<NavigationProperty,PropertyInfo>(navProperty, baseProperty));
1369 private void EmitCollectionProperty(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, NavigationProperty navProperty)
1371 const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
1372 MethodInfo baseSetter = baseProperty.GetSetMethod(true); ;
1373 MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask;
1375 string cannotSetException = System.Data.Entity.Strings.EntityProxyTypeInfo_CannotSetEntityCollectionProperty(propertyBuilder.Name, typeBuilder.Name);
1376 MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType });
1377 ILGenerator generator = setterBuilder.GetILGenerator();
1378 Label instanceEqual = generator.DefineLabel();
1379 generator.Emit(OpCodes.Ldarg_1);
1380 generator.Emit(OpCodes.Ldarg_0);
1381 generator.Emit(OpCodes.Call, _getRelationshipManager);
1382 generator.Emit(OpCodes.Ldstr, navProperty.RelationshipType.FullName);
1383 generator.Emit(OpCodes.Ldstr, navProperty.ToEndMember.Name);
1384 generator.Emit(OpCodes.Callvirt, s_GetRelatedEnd);
1385 generator.Emit(OpCodes.Beq_S, instanceEqual);
1386 generator.Emit(OpCodes.Ldstr, cannotSetException);
1387 generator.Emit(OpCodes.Newobj, s_InvalidOperationConstructor);
1388 generator.Emit(OpCodes.Throw);
1389 generator.MarkLabel(instanceEqual);
1390 generator.Emit(OpCodes.Ldarg_0);
1391 generator.Emit(OpCodes.Ldarg_1);
1392 generator.Emit(OpCodes.Call, baseProperty.GetSetMethod(true));
1393 generator.Emit(OpCodes.Ret);
1394 propertyBuilder.SetSetMethod(setterBuilder);
1396 _collectionProperties.Add(new KeyValuePair<NavigationProperty, PropertyInfo>(navProperty, baseProperty));
1399 #region Interface Implementation
1401 private void ImplementIEntityWithChangeTracker(TypeBuilder typeBuilder, Action<FieldBuilder, bool> registerField)
1403 _changeTrackerField = typeBuilder.DefineField("_changeTracker", typeof(IEntityChangeTracker), FieldAttributes.Private);
1404 registerField(_changeTrackerField, false);
1406 // Implement EntityMemberChanging(string propertyName)
1407 _entityMemberChanging = typeBuilder.DefineMethod("EntityMemberChanging", MethodAttributes.Private | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(string) });
1408 ILGenerator generator = _entityMemberChanging.GetILGenerator();
1409 Label methodEnd = generator.DefineLabel();
1410 generator.Emit(OpCodes.Ldarg_0);
1411 generator.Emit(OpCodes.Ldfld, _changeTrackerField);
1412 generator.Emit(OpCodes.Brfalse_S, methodEnd);
1413 generator.Emit(OpCodes.Ldarg_0);
1414 generator.Emit(OpCodes.Ldfld, _changeTrackerField);
1415 generator.Emit(OpCodes.Ldarg_1);
1416 generator.Emit(OpCodes.Callvirt, s_EntityMemberChanging);
1417 generator.MarkLabel(methodEnd);
1418 generator.Emit(OpCodes.Ret);
1420 // Implement EntityMemberChanged(string propertyName)
1421 _entityMemberChanged = typeBuilder.DefineMethod("EntityMemberChanged", MethodAttributes.Private | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(string) });
1422 generator = _entityMemberChanged.GetILGenerator();
1423 methodEnd = generator.DefineLabel();
1424 generator.Emit(OpCodes.Ldarg_0);
1425 generator.Emit(OpCodes.Ldfld, _changeTrackerField);
1426 generator.Emit(OpCodes.Brfalse_S, methodEnd);
1427 generator.Emit(OpCodes.Ldarg_0);
1428 generator.Emit(OpCodes.Ldfld, _changeTrackerField);
1429 generator.Emit(OpCodes.Ldarg_1);
1430 generator.Emit(OpCodes.Callvirt, s_EntityMemberChanged);
1431 generator.MarkLabel(methodEnd);
1432 generator.Emit(OpCodes.Ret);
1434 // Implement IEntityWithChangeTracker.SetChangeTracker(IEntityChangeTracker changeTracker)
1435 MethodBuilder setChangeTracker = typeBuilder.DefineMethod("SetChangeTracker", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
1436 typeof(void), new Type[] { typeof(IEntityChangeTracker) });
1437 generator = setChangeTracker.GetILGenerator();
1438 generator.Emit(OpCodes.Ldarg_0);
1439 generator.Emit(OpCodes.Ldarg_1);
1440 generator.Emit(OpCodes.Stfld, _changeTrackerField);
1441 generator.Emit(OpCodes.Ret);
1444 private void ImplementIEntityWithRelationships(TypeBuilder typeBuilder, Action<FieldBuilder, bool> registerField)
1446 _relationshipManagerField = typeBuilder.DefineField("_relationshipManager", typeof(RelationshipManager), FieldAttributes.Private);
1447 registerField(_relationshipManagerField, true);
1449 PropertyBuilder relationshipManagerProperty = typeBuilder.DefineProperty("RelationshipManager", System.Reflection.PropertyAttributes.None, typeof(RelationshipManager), Type.EmptyTypes);
1451 // Implement IEntityWithRelationships.get_RelationshipManager
1452 _getRelationshipManager = typeBuilder.DefineMethod("get_RelationshipManager", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final,
1453 typeof(RelationshipManager), Type.EmptyTypes);
1454 ILGenerator generator = _getRelationshipManager.GetILGenerator();
1455 Label trueLabel = generator.DefineLabel();
1456 generator.Emit(OpCodes.Ldarg_0);
1457 generator.Emit(OpCodes.Ldfld, _relationshipManagerField);
1458 generator.Emit(OpCodes.Brtrue_S, trueLabel);
1459 generator.Emit(OpCodes.Ldarg_0);
1460 generator.Emit(OpCodes.Ldarg_0);
1461 generator.Emit(OpCodes.Call, s_CreateRelationshipManager);
1462 generator.Emit(OpCodes.Stfld, _relationshipManagerField);
1463 generator.MarkLabel(trueLabel);
1464 generator.Emit(OpCodes.Ldarg_0);
1465 generator.Emit(OpCodes.Ldfld, _relationshipManagerField);
1466 generator.Emit(OpCodes.Ret);
1467 relationshipManagerProperty.SetGetMethod(_getRelationshipManager);
1474 /// Add a DataContractAttribute to the proxy type, based on one that may have been applied to the base type.
1478 /// From http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx:
1480 /// A data contract has two basic requirements: a stable name and a list of members.
1481 /// The stable name consists of the namespace uniform resource identifier (URI) and the local name of the contract.
1482 /// By default, when you apply the DataContractAttribute to a class,
1483 /// it uses the class name as the local name and the class's namespace (prefixed with "http://schemas.datacontract.org/2004/07/")
1484 /// as the namespace URI. You can override the defaults by setting the Name and Namespace properties.
1485 /// You can also change the namespace by applying the ContractNamespaceAttribute to the namespace.
1486 /// Use this capability when you have an existing type that processes data exactly as you require
1487 /// but has a different namespace and class name from the data contract.
1488 /// By overriding the default values, you can reuse your existing type and have the serialized data conform to the data contract.
1491 /// The first attempt at WCF serialization of proxies involved adding a DataContractAttribute to the proxy type in such a way
1492 /// so that the name and namespace of the proxy's data contract matched that of the base class.
1493 /// This worked when serializing proxy objects for the root type of the DataContractSerializer,
1494 /// but not for proxy objects of types derived from the root type.
1496 /// Attempting to add the proxy type to the list of known types failed as well,
1497 /// since the data contract of the proxy type did not match the base type as intended.
1498 /// This was due to the fact that inheritance is captured in the data contract.
1499 /// So while the proxy and base data contracts had the same members, the proxy data contract differed in that is declared itself
1500 /// as an extension of the base data contract. So the data contracts were technically not equivalent.
1502 /// The approach used instead is to allow proxy types to have their own DataContract.
1503 /// Users then have at least two options available to them.
1505 /// The first approach is to add the proxy types to the list of known types.
1507 /// The second approach is to implement an IDataContractSurrogate that can map a proxy instance to a surrogate that does have a data contract
1508 /// equivalent to the base type (you could use the base type itself for this purpose).
1509 /// While more complex to implement, it allows services to hide the use of proxies from clients.
1510 /// This can be quite useful in order to maximize potential interoperability.
1513 internal sealed class DataContractImplementor
1515 private static readonly ConstructorInfo s_DataContractAttributeConstructor = typeof(DataContractAttribute).GetConstructor(Type.EmptyTypes);
1516 private static readonly PropertyInfo[] s_DataContractProperties = new PropertyInfo[] {
1517 typeof(DataContractAttribute).GetProperty("IsReference")
1520 private readonly Type _baseClrType;
1521 private readonly DataContractAttribute _dataContract;
1523 internal DataContractImplementor(EntityType ospaceEntityType)
1525 _baseClrType = ospaceEntityType.ClrType;
1527 DataContractAttribute[] attributes = (DataContractAttribute[])_baseClrType.GetCustomAttributes(typeof(DataContractAttribute), false);
1528 if (attributes.Length > 0)
1530 _dataContract = attributes[0];
1534 internal void Implement(TypeBuilder typeBuilder, Action<FieldBuilder, bool> registerField)
1536 if (_dataContract != null)
1538 // Use base data contract properties to help determine values of properties the proxy type's data contract.
1539 object[] propertyValues = new object[] {
1541 _dataContract.IsReference
1544 CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(s_DataContractAttributeConstructor, new object[0], s_DataContractProperties, propertyValues);
1545 typeBuilder.SetCustomAttribute(attributeBuilder);
1551 /// This class determines if the proxied type implements ISerializable with the special serialization constructor.
1552 /// If it does, it adds the appropriate members to the proxy type.
1554 internal sealed class ISerializableImplementor
1556 private readonly Type _baseClrType;
1557 private readonly bool _baseImplementsISerializable;
1558 private readonly bool _canOverride;
1559 private readonly MethodInfo _getObjectDataMethod;
1560 private readonly ConstructorInfo _serializationConstructor;
1562 internal ISerializableImplementor(EntityType ospaceEntityType)
1564 _baseClrType = ospaceEntityType.ClrType;
1565 _baseImplementsISerializable = _baseClrType.IsSerializable && typeof(ISerializable).IsAssignableFrom(_baseClrType);
1567 if (_baseImplementsISerializable)
1569 // Determine if interface implementation can be overridden.
1570 // Fortunately, there's only one method to check.
1571 InterfaceMapping mapping = _baseClrType.GetInterfaceMap(typeof(ISerializable));
1572 _getObjectDataMethod = mapping.TargetMethods[0];
1574 // Members that implement interfaces must be public, unless they are explicitly implemented, in which case they are private and sealed (at least for C#).
1575 bool canOverrideMethod = (_getObjectDataMethod.IsVirtual && !_getObjectDataMethod.IsFinal) && _getObjectDataMethod.IsPublic;
1577 if (canOverrideMethod)
1579 // Determine if proxied type provides the special serialization constructor.
1580 // In order for the proxy class to properly support ISerializable, this constructor must not be private.
1581 _serializationConstructor = _baseClrType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }, null);
1583 _canOverride = _serializationConstructor != null && (_serializationConstructor.IsPublic || _serializationConstructor.IsFamily || _serializationConstructor.IsFamilyOrAssembly);
1586 Debug.Assert(!(_canOverride && (_getObjectDataMethod == null || _serializationConstructor == null)), "Both GetObjectData method and Serialization Constructor must be present when proxy overrides ISerializable implementation.");
1590 internal bool TypeIsSuitable
1595 // either proxied type doesn't implement ISerializable,
1596 // or it does and it can be suitably overridden.
1597 return !_baseImplementsISerializable || _canOverride;
1601 internal bool TypeImplementsISerializable
1605 return _baseImplementsISerializable;
1609 internal void Implement(TypeBuilder typeBuilder, IEnumerable<FieldBuilder> serializedFields)
1611 if (_baseImplementsISerializable && _canOverride)
1613 PermissionSet serializationFormatterPermissions = new PermissionSet(null);
1614 serializationFormatterPermissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
1616 Type[] parameterTypes = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) };
1617 MethodInfo getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) });
1618 MethodInfo addValue = typeof(SerializationInfo).GetMethod("AddValue", new Type[] { typeof(string), typeof(object), typeof(Type) });
1619 MethodInfo getValue = typeof(SerializationInfo).GetMethod("GetValue", new Type[] { typeof(string), typeof(Type) });
1622 // Define GetObjectData method override
1624 // [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
1625 // public void GetObjectData(SerializationInfo info, StreamingContext context)
1627 MethodBuilder proxyGetObjectData = typeBuilder.DefineMethod(_getObjectDataMethod.Name,
1628 MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual,
1631 proxyGetObjectData.AddDeclarativeSecurity(SecurityAction.Demand, serializationFormatterPermissions);
1634 ILGenerator generator = proxyGetObjectData.GetILGenerator();
1636 // Call SerializationInfo.AddValue to serialize each field value
1637 foreach (FieldBuilder field in serializedFields)
1639 generator.Emit(OpCodes.Ldarg_1);
1640 generator.Emit(OpCodes.Ldstr, field.Name);
1641 generator.Emit(OpCodes.Ldarg_0);
1642 generator.Emit(OpCodes.Ldfld, field);
1643 generator.Emit(OpCodes.Ldtoken, field.FieldType);
1644 generator.Emit(OpCodes.Call, getTypeFromHandle);
1645 generator.Emit(OpCodes.Callvirt, addValue);
1648 // Emit call to base method
1649 generator.Emit(OpCodes.Ldarg_0);
1650 generator.Emit(OpCodes.Ldarg_1);
1651 generator.Emit(OpCodes.Ldarg_2);
1652 generator.Emit(OpCodes.Call, _getObjectDataMethod);
1653 generator.Emit(OpCodes.Ret);
1657 // Define serialization constructor
1659 // [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
1660 // .ctor(SerializationInfo info, StreamingContext context)
1662 MethodAttributes constructorAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
1663 constructorAttributes |= _serializationConstructor.IsPublic? MethodAttributes.Public : MethodAttributes.Private;
1665 ConstructorBuilder proxyConstructor = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard | CallingConventions.HasThis, parameterTypes);
1666 proxyConstructor.AddDeclarativeSecurity(SecurityAction.Demand, serializationFormatterPermissions);
1669 //Emit call to base serialization constructor
1670 ILGenerator generator = proxyConstructor.GetILGenerator();
1671 generator.Emit(OpCodes.Ldarg_0);
1672 generator.Emit(OpCodes.Ldarg_1);
1673 generator.Emit(OpCodes.Ldarg_2);
1674 generator.Emit(OpCodes.Call, _serializationConstructor);
1676 // Call SerializationInfo.GetValue to retrieve the value of each field
1677 foreach (FieldBuilder field in serializedFields)
1679 generator.Emit(OpCodes.Ldarg_0);
1680 generator.Emit(OpCodes.Ldarg_1);
1681 generator.Emit(OpCodes.Ldstr, field.Name);
1682 generator.Emit(OpCodes.Ldtoken, field.FieldType);
1683 generator.Emit(OpCodes.Call, getTypeFromHandle);
1684 generator.Emit(OpCodes.Callvirt, getValue);
1685 generator.Emit(OpCodes.Castclass, field.FieldType);
1686 generator.Emit(OpCodes.Stfld, field);
1689 generator.Emit(OpCodes.Ret);