示例#1
0
文件: Adapter.cs 项目: MingLu8/Nemo
        private static void DefineGuardedProperty(PropertyInfo property, TypeBuilder typeBuilder, FieldInfo field, Type objectType, IEntityMap entityMap)
        {
            // create the new property.
            var propertyBuilder = typeBuilder.DefineProperty(property.Name, System.Reflection.PropertyAttributes.HasDefault, property.PropertyType, null);

            // The property "set" and property "get" methods require a special set of attributes.
            //var getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
            var getSetAttr = MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName;

            // create the getter if we can read.
            if (property.CanRead)
            {
                // create the get method for the property.
                var getMethodName = "get_" + property.Name;
                var getMethod     = typeBuilder.DefineMethod(getMethodName, getSetAttr, property.PropertyType, Type.EmptyTypes);

                // get the IL generator to generate the required IL.
                ILGenerator il = getMethod.GetILGenerator();

                // directly call the inner object's get method of the property.
                if (Reflector.IsDataEntityList(property.PropertyType, out var elementType))
                {
                    var isInterface      = property.PropertyType.GetGenericTypeDefinition() == typeof(IList <>);
                    var asReadOnlyMethod = typeof(ObjectExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "AsReadOnly").First(m => m.GetParameters()[0].ParameterType.Name == (isInterface ? "IList`1" : "List`1"));

                    var result = il.DeclareLocal(property.PropertyType);

                    // load the first argument (the instance itself) and the field.
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldfld, field);
                    il.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null);

                    il.Emit(OpCodes.Call, asReadOnlyMethod.MakeGenericMethod(elementType));

                    il.Emit(OpCodes.Stloc_0, result);
                    il.Emit(OpCodes.Ldloc_0);
                }
                else if (Reflector.IsDataEntity(property.PropertyType))
                {
                    var asReadOnlyMethod = typeof(ObjectExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "AsReadOnly").First(m => m.GetParameters()[0].ParameterType.IsGenericParameter);

                    var result = il.DeclareLocal(property.PropertyType);

                    // load the first argument (the instance itself) and the field.
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldfld, field);
                    il.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null);

                    il.Emit(OpCodes.Call, asReadOnlyMethod.MakeGenericMethod(property.PropertyType));

                    il.Emit(OpCodes.Stloc_0, result);
                    il.Emit(OpCodes.Ldloc_0);
                }
                else if (property.DeclaringType.InheritsFrom(typeof(ITrackableDataEntity)) && property.PropertyType == typeof(ObjectState) && property.Name == "ObjectState")
                {
                    il.Emit(OpCodes.Ldc_I4, (int)ObjectState.ReadOnly);
                }
                else
                {
                    // load the first argument (the instance itself) and the field.
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldfld, field);
                    il.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null);
                }

                il.Emit(OpCodes.Ret);

                // set the method.
                propertyBuilder.SetGetMethod(getMethod);
                typeBuilder.DefineMethodOverride(getMethod, property.ReflectedType.GetMethod(getMethodName));
            }

            // create the setter if we can read.
            if (property.CanWrite)
            {
                // create the set method of the property.
                var setMethodName = "set_" + property.Name;
                var setMethod     = typeBuilder.DefineMethod(setMethodName, getSetAttr, null, new Type[] { property.PropertyType });

                // get the IL generator to generate some IL.
                ILGenerator il = setMethod.GetILGenerator();

                // load the first argument (instance itself) and the field.
                il.Emit(OpCodes.Newobj, typeof(NotSupportedException).GetConstructor(Type.EmptyTypes));
                il.Emit(OpCodes.Throw);

                propertyBuilder.SetSetMethod(setMethod);
                typeBuilder.DefineMethodOverride(setMethod, property.ReflectedType.GetMethod(setMethodName));
            }
        }