private static void FindNextProperty(PropertyInfo property, IList<PropertyInfo> collection, bool getter) { DebugCheck.NotNull(property); DebugCheck.NotNull(collection); var method = getter ? property.Getter() : property.Setter(); if (method != null) { var nextType = method.DeclaringType.BaseType(); if (nextType != null && nextType != typeof(object)) { var baseMethod = method.GetBaseDefinition(); var nextProperty = (from p in nextType.GetInstanceProperties() let candidateMethod = getter ? p.Getter() : p.Setter() where candidateMethod != null && candidateMethod.GetBaseDefinition() == baseMethod select p).FirstOrDefault(); if (nextProperty != null) { collection.Add(nextProperty); CollectProperties(nextProperty, collection); } } } }
private static void EmitBaseSetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty) { if (CanProxySetter(baseProperty)) { var baseSetter = baseProperty.Setter(); const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual; var methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask; var setterBuilder = typeBuilder.DefineMethod( "set_" + baseProperty.Name, methodAccess | methodAttributes, null, new[] { baseProperty.PropertyType }); var generator = setterBuilder.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Call, baseSetter); generator.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(setterBuilder); } }
internal static bool CanProxySetter(PropertyInfo clrProperty) { DebugCheck.NotNull(clrProperty); return CanProxyMethod(clrProperty.Setter()); }
private void EmitCollectionProperty( TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, NavigationProperty navProperty) { const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual; var baseSetter = baseProperty.Setter(); var methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask; var cannotSetException = Strings.EntityProxyTypeInfo_CannotSetEntityCollectionProperty(propertyBuilder.Name, typeBuilder.Name); var setterBuilder = typeBuilder.DefineMethod( "set_" + baseProperty.Name, methodAccess | methodAttributes, null, new[] { baseProperty.PropertyType }); var generator = setterBuilder.GetILGenerator(); var instanceEqual = generator.DefineLabel(); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Call, _getRelationshipManager); generator.Emit(OpCodes.Ldstr, navProperty.RelationshipType.FullName); generator.Emit(OpCodes.Ldstr, navProperty.ToEndMember.Name); generator.Emit(OpCodes.Callvirt, GetRelatedEndMethod); generator.Emit(OpCodes.Beq_S, instanceEqual); generator.Emit(OpCodes.Ldstr, cannotSetException); generator.Emit(OpCodes.Newobj, _invalidOperationConstructorMethod); generator.Emit(OpCodes.Throw); generator.MarkLabel(instanceEqual); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Call, baseProperty.Setter()); generator.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(setterBuilder); _collectionProperties.Add(new KeyValuePair<NavigationProperty, PropertyInfo>(navProperty, baseProperty)); }
private void EmitReferenceProperty( TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, NavigationProperty navProperty) { const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual; var baseSetter = baseProperty.Setter(); var methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask; var specificGetRelatedReference = GetRelatedReferenceMethod.MakeGenericMethod(baseProperty.PropertyType); var specificEntityReferenceSetValue = typeof(EntityReference<>).MakeGenericType(baseProperty.PropertyType).GetOnlyDeclaredMethod( "set_Value"); var setterBuilder = typeBuilder.DefineMethod( "set_" + baseProperty.Name, methodAccess | methodAttributes, null, new[] { baseProperty.PropertyType }); var generator = setterBuilder.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Callvirt, _getRelationshipManager); generator.Emit(OpCodes.Ldstr, navProperty.RelationshipType.FullName); generator.Emit(OpCodes.Ldstr, navProperty.ToEndMember.Name); generator.Emit(OpCodes.Callvirt, specificGetRelatedReference); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Callvirt, specificEntityReferenceSetValue); generator.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(setterBuilder); _referenceProperties.Add(new KeyValuePair<NavigationProperty, PropertyInfo>(navProperty, baseProperty)); }
private void EmitScalarSetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, bool isKeyMember) { var baseSetter = baseProperty.Setter(); const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual; var methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask; var setterBuilder = typeBuilder.DefineMethod( "set_" + baseProperty.Name, methodAccess | methodAttributes, null, new[] { baseProperty.PropertyType }); var generator = setterBuilder.GetILGenerator(); var endOfMethod = generator.DefineLabel(); // If the CLR property represents a key member of the Entity Type, // ignore attempts to set the key value to the same value. if (isKeyMember) { var baseGetter = baseProperty.Getter(); if (baseGetter != null) { // if (base.[Property] != value) // { // // perform set operation // } var propertyType = baseProperty.PropertyType; if (propertyType == typeof(int) || propertyType == typeof(short) || propertyType == typeof(Int64) || propertyType == typeof(bool) || propertyType == typeof(byte) || propertyType == typeof(UInt32) || propertyType == typeof(UInt64) || propertyType == typeof(float) || propertyType == typeof(double) || propertyType.IsEnum()) { generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Call, baseGetter); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Beq_S, endOfMethod); } else if (propertyType == typeof(byte[])) { // Byte arrays must be compared by value generator.Emit(OpCodes.Ldsfld, _compareByteArraysField); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Call, baseGetter); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Callvirt, FuncInvokeMethod); generator.Emit(OpCodes.Brtrue_S, endOfMethod); } else { // Get the specific type's inequality method if it exists var op_inequality = propertyType.GetDeclaredMethod("op_Inequality", propertyType, propertyType); if (op_inequality != null) { generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Call, baseGetter); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Call, op_inequality); generator.Emit(OpCodes.Brfalse_S, endOfMethod); } else { // Use object inequality generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Call, baseGetter); if (propertyType.IsValueType()) { generator.Emit(OpCodes.Box, propertyType); } generator.Emit(OpCodes.Ldarg_1); if (propertyType.IsValueType()) { generator.Emit(OpCodes.Box, propertyType); } generator.Emit(OpCodes.Call, ObjectEqualsMethod); generator.Emit(OpCodes.Brtrue_S, endOfMethod); } } } } // Creates code like this: // // try // { // MemberChanging(propertyName); // base.Property_set(value); // MemberChanged(propertyName); // } // finally // { // _resetFKSetterFlagField(this); // } // // Note that the try/finally ensures that even if an exception causes // the setting of the property to be aborted, we still clear the flag that // indicates that we are in a property setter. generator.BeginExceptionBlock(); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldstr, baseProperty.Name); generator.Emit(OpCodes.Call, _entityMemberChanging); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Call, baseSetter); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldstr, baseProperty.Name); generator.Emit(OpCodes.Call, _entityMemberChanged); generator.BeginFinallyBlock(); generator.Emit(OpCodes.Ldsfld, _resetFKSetterFlagField); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Callvirt, InvokeMethod); generator.EndExceptionBlock(); generator.MarkLabel(endOfMethod); generator.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(setterBuilder); }