Exemplo n.º 1
0
        public static IEnumerable <System.Reflection.PropertyInfo> GetPropertiesOrderForInterface(Type TModel)
        {
            if (!TModel.IsInterface)
            {
                throw new InvalidOperationException("El modelo <TModel> debe ser una interfaz");
            }

            //obtenemos las propiedades del tipo de interfaz del modelo
            var properties = TModel
                             .GetProperties()
                             .OrderByDescending(x => PointerCastHelper.TypeSizeInMemory(x.PropertyType));//así quedan las de tamaño variable al final.

            return(properties);
        }
Exemplo n.º 2
0
        private static Type BuildWrapperType(Type interface_type)
        {
            //si anteriormente se había creado un tipo para esta interfaz lo devolvemos.
            if (generated_types_cache.ContainsKey(interface_type))
            {
                return(generated_types_cache[interface_type]);
            }

            string type_name =
                interface_type.FullName.Replace('.', '_') +
                Constants.WRAPPER_TYPE_NAME_SUFIX;

            //definimos la nueva classe wrapper.
            TypeBuilder type_builder = module_builder.DefineType(type_name,
                                                                 TypeAttributes.Class |
                                                                 TypeAttributes.Public |
                                                                 TypeAttributes.AutoClass |
                                                                 TypeAttributes.AnsiClass,
                                                                 null,
                                                                 Type.EmptyTypes);

            //Añadimos la implementación de la interfaz del modelo.
            type_builder.AddInterfaceImplementation(interface_type);

            //creamos una variable estática en cla clase que contendrá
            //un puntero al array de bytes del origen de datos.
            FieldBuilder data_field = type_builder
                                      .DefineField("data", typeof(Byte[]),
                                                   FieldAttributes.Public | FieldAttributes.Static);

            //creamos otra variable para almacenar el offset del registro actual
            FieldBuilder offset_field = type_builder
                                        .DefineField("offset", typeof(long), FieldAttributes.Public);

            //obtenemos las propiedades del tipo de interfaz del modelo
            var properties = SerializationHelper.GetPropertiesOrderForInterface(interface_type);

            //offset de la propiedad dentro del conjunto de bytes del registro.
            int prop_offset         = 0;
            int first_string_offset = -1;
            int string_index        = 0;

            //implementamos las propiedades
            foreach (var prop in properties)
            {
                //método de transformación del array de bytes al tipo de la propiedad.
                string cast_method_name = PointerCastHelper.GetByteToTypeMethod(prop.PropertyType);

                PropertyBuilder prop_builder = type_builder
                                               .DefineProperty(prop.Name,
                                                               PropertyAttributes.HasDefault,
                                                               prop.PropertyType,
                                                               Type.EmptyTypes);

                //definimos el método get
                MethodBuilder pGet = type_builder.DefineMethod("get_" + prop.Name,
                                                               MethodAttributes.Virtual |
                                                               MethodAttributes.Public |
                                                               MethodAttributes.SpecialName |
                                                               MethodAttributes.HideBySig,
                                                               prop.PropertyType, Type.EmptyTypes);

                var getIl = pGet.GetILGenerator();

                //emitimos el código que convierte el array de bytes encontrado en el
                //offset de la variable del modelo a un puntero del tipo de retorno.
                if (prop.PropertyType == typeof(string))
                {
                    if (first_string_offset == -1)
                    {
                        first_string_offset = prop_offset;
                    }

                    //llamámos al método que nos dá el offset de este índice de string. GetStringOffsetAtIndex
                    getIl.Emit(OpCodes.Ldsfld, data_field);
                    getIl.Emit(OpCodes.Ldarg_0);
                    //sumamos el offset del primer campo con el del registro
                    getIl.Emit(OpCodes.Ldfld, offset_field);
                    getIl.Emit(OpCodes.Ldc_I4, prop_offset);
                    getIl.Emit(OpCodes.Conv_I8);
                    getIl.Emit(OpCodes.Add);
                    //añadimos el indice del string que estamos cargando.
                    getIl.Emit(OpCodes.Ldc_I4, string_index++);
                    //obtenemos el offset del string.
                    getIl.Emit(OpCodes.Call, typeof(PointerCastHelper).GetMethod("GetStringAtOffset"));
                    getIl.Emit(OpCodes.Ret);
                }
                else
                {
                    getIl.Emit(OpCodes.Nop);
                    getIl.Emit(OpCodes.Ldsfld, data_field);
                    getIl.Emit(OpCodes.Ldarg_0);
                    getIl.Emit(OpCodes.Ldfld, offset_field);
                    getIl.Emit(OpCodes.Ldc_I4, prop_offset);
                    getIl.Emit(OpCodes.Conv_I8);
                    getIl.Emit(OpCodes.Add);
                    getIl.Emit(OpCodes.Call, typeof(PointerCastHelper).GetMethod(PointerCastHelper.GetByteToTypeMethod(prop.PropertyType)));
                    getIl.Emit(OpCodes.Ret);
                    prop_offset += PointerCastHelper.TypeSizeInMemory(prop.PropertyType);
                }

                prop_builder.SetGetMethod(pGet);

                type_builder.DefineMethodOverride(pGet, interface_type.GetMethod("get_" + prop.Name));
            }


            //Añadimos el nuevo tipo a la caché de creación.
            Type created = type_builder.CreateType();

            generated_types_cache.Add(interface_type, created);
            return(created);
        }