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); } } } }
public bool EmitMember( TypeBuilder typeBuilder, EdmMember member, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, BaseProxyImplementor baseImplementor) { if (_members.Contains(member)) { var baseGetter = baseProperty.Getter(); const MethodAttributes getterAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual; var getterAccess = baseGetter.Attributes & MethodAttributes.MemberAccessMask; // Define field to store interceptor Func // Signature of interceptor Func delegate is as follows: // // bool intercept(ProxyType proxy, PropertyType propertyValue) // // where // PropertyType is the type of the Property, such as ICollection<Customer>, // ProxyType is the type of the proxy object, // propertyValue is the value returned from the proxied type's property getter. var interceptorType = typeof(Func<,,>).MakeGenericType(typeBuilder, baseProperty.PropertyType, typeof(bool)); var interceptorInvoke = TypeBuilder.GetMethod(interceptorType, typeof(Func<,,>).GetOnlyDeclaredMethod("Invoke")); var interceptorField = typeBuilder.DefineField( GetInterceptorFieldName(baseProperty.Name), interceptorType, FieldAttributes.Private | FieldAttributes.Static); // Define a property getter override in the proxy type var getterBuilder = typeBuilder.DefineMethod( "get_" + baseProperty.Name, getterAccess | getterAttributes, baseProperty.PropertyType, Type.EmptyTypes); var generator = getterBuilder.GetILGenerator(); // Emit instructions for the following call: // T value = base.SomeProperty; // if(this._interceptorForSomeProperty(this, value)) // { return value; } // return base.SomeProperty; // where _interceptorForSomeProperty represents the interceptor Func field. var lableTrue = generator.DefineLabel(); generator.DeclareLocal(baseProperty.PropertyType); // T value generator.Emit(OpCodes.Ldarg_0); // call base.SomeProperty generator.Emit(OpCodes.Call, baseGetter); // call to base property getter generator.Emit(OpCodes.Stloc_0); // value = result generator.Emit(OpCodes.Ldarg_0); // load this generator.Emit(OpCodes.Ldfld, interceptorField); // load this._interceptor generator.Emit(OpCodes.Ldarg_0); // load this generator.Emit(OpCodes.Ldloc_0); // load value generator.Emit(OpCodes.Callvirt, interceptorInvoke); // call to interceptor delegate with (this, value) generator.Emit(OpCodes.Brtrue_S, lableTrue); // if true, just return generator.Emit(OpCodes.Ldarg_0); // else, call the base propertty getter again generator.Emit(OpCodes.Call, baseGetter); // call to base property getter generator.Emit(OpCodes.Ret); generator.MarkLabel(lableTrue); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getterBuilder); baseImplementor.AddBasePropertyGetter(baseProperty); return true; } return false; }
internal static bool CanProxyGetter(PropertyInfo clrProperty) { DebugCheck.NotNull(clrProperty); return CanProxyMethod(clrProperty.Getter()); }
private static void EmitBaseGetter(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty) { if (CanProxyGetter(baseProperty)) { var baseGetter = baseProperty.Getter(); const MethodAttributes getterAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual; var getterAccess = baseGetter.Attributes & MethodAttributes.MemberAccessMask; // Define a property getter override in the proxy type var getterBuilder = typeBuilder.DefineMethod( "get_" + baseProperty.Name, getterAccess | getterAttributes, baseProperty.PropertyType, Type.EmptyTypes); var gen = getterBuilder.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Call, baseGetter); gen.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getterBuilder); } }
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); }