示例#1
0
        /// <summary>
        /// Генерирует объект с метаданными типа в соответствии с заданными атрибутами <see cref="AmfObjectAttribute"/>, с полями типа, заданного в атрибутах <see cref="AmfMemberAttribute"/>.
        /// </summary>
        /// <param name="sourceObject">Исходный экземпляр объекта.</param>
        /// <returns></returns>
        private static object GenerateType <T>(T sourceObject)
        {
            Type sourceType = sourceObject.GetType(); // Получаем метаданные типа исходного объекта.

            if (sourceType.IsDictionary())
            {
                return(GenerateType(sourceObject as IEnumerable <KeyValuePair <string, object> >));
            }
            if (!sourceType.IsDefinedAttribute <AmfObjectAttribute>())
            {
                return(sourceObject);                                                                             // Если у типа объекта не задан атрибут - возвращаем как есть.
            }
            string      typeName    = sourceType.GetAttribute <AmfObjectAttribute>().Name ?? sourceType.FullName; // Определяем имя у типа.
            Type        definedType = moduleBuilder.GetType(typeName);                                            // Пытаемся найти уже определенный в сборке тип.
            TypeBuilder typeBuilder = null;                                                                       // Определяем билдер для нашего типа.

            Dictionary <string, object> properties = new Dictionary <string, object>();                           // Словарь свойств объекта.
            Dictionary <string, object> fields     = new Dictionary <string, object>();                           // Словарь полей объекта.

            // Если тип в сборке еще не определен...
            if (definedType == null)
            {
                typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);                                                          // Опледеляем тип с нашим именем.

                ConstructorBuilder ctor   = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); // Определяем конструктор.
                ILGenerator        ctorIL = ctor.GetILGenerator();                                                                                // Получаем ссылку на генератор MSIL-инструкций для конструктора.
                ctorIL.Emit(OpCodes.Ldarg_0);                                                                                                     // Помещаем в стек вычислений нулевой аргумент.
                ctorIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));                                                        // Вызываем базовый конструктор для инициализации значения по умолчанию у нулевого аргумента.
                ctorIL.Emit(OpCodes.Ret);                                                                                                         // Помещаем в стек вычислений инструкцию о возврате из метода.

                // Перебираем все свойства нашего типа.
                foreach (PropertyInfo propertyInfo in sourceType.GetProperties())
                {
                    AmfMemberAttribute attribute = propertyInfo.GetAttribute <AmfMemberAttribute>();  // Получаем наш кастомный атрибут типа AmfMemberAttribute.

                    if (attribute == null)
                    {
                        continue;                                                     // Если атрибут не указан - пропускаем свойство.
                    }
                    string propertyName  = attribute.Name ?? propertyInfo.Name;       // Получаем имя свойства.
                    object propertyValue = propertyInfo.GetValue(sourceObject, null); // Получаем значение свойства.
                    Type   propertyType  = propertyInfo.PropertyType;                 // Получаем метаданные типа свойства.

                    // Если у типа задан атрибут или это словарь...
                    if (propertyInfo.PropertyType.IsDefinedAttribute <AmfObjectAttribute>() || propertyType.IsDictionary())
                    {
                        // Генерируем объект типа, заданного в атрибуте.
                        propertyValue = propertyType.IsDictionary()
                            ? GenerateType(propertyValue as IEnumerable <KeyValuePair <string, object> >)
                            : GenerateType(propertyValue);

                        propertyType = propertyValue.GetType();   // Обновляем тип свойства.
                    }

                    FieldBuilder     fieldBuilder    = typeBuilder.DefineField($"m_{propertyName}", propertyType, FieldAttributes.Private);             // Определяем новое приватное поле.
                    PropertyBuilder  propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);     // Определяем новое свойство.
                    MethodAttributes getSetAttr      = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;             // Устанавливаем атрибуты аксессору и мутатору свойства.

                    MethodBuilder methodBuilderAccessor = typeBuilder.DefineMethod($"get_{propertyName}", getSetAttr, propertyType, Type.EmptyTypes);   // Определяем аксессор.
                    ILGenerator   accessorIL            = methodBuilderAccessor.GetILGenerator();                                                       // Получаем ссылку на генератор MSIL-инструкций для аксессора.
                    accessorIL.Emit(OpCodes.Ldarg_0);                                                                                                   // Помещаем в стек вычислений нулевой аргумент.
                    accessorIL.Emit(OpCodes.Ldfld, fieldBuilder);                                                                                       // Помещаем в стек вычислений инструкцию о получении значения по ссылке поля.
                    accessorIL.Emit(OpCodes.Ret);                                                                                                       // Помещаем в стек вычислений инструкцию о возврате из метода.
                    MethodBuilder methodBuilderSetter = typeBuilder.DefineMethod($"set_{propertyName}", getSetAttr, null, new Type[] { propertyType }); // Определяем мутатор.
                    ILGenerator   setterIL            = methodBuilderSetter.GetILGenerator();                                                           // Получаем ссылку на генератор MSIL-инструкций для мутатора.
                    setterIL.Emit(OpCodes.Ldarg_0);                                                                                                     // Помещаем в стек вычислений нулевой аргумент.
                    setterIL.Emit(OpCodes.Ldarg_1);                                                                                                     // Помещаем в стек вычислений первый аргумент.
                    setterIL.Emit(OpCodes.Stfld, fieldBuilder);                                                                                         // Помещаем в стек вычислений инструкцию о сохранении значения по ссылке поля.
                    setterIL.Emit(OpCodes.Ret);                                                                                                         // Помещаем в стек вычислений инструкцию о возврате из метода.

                    propertyBuilder.SetGetMethod(methodBuilderAccessor);                                                                                // Добавляем свойству аксессор.
                    propertyBuilder.SetSetMethod(methodBuilderSetter);                                                                                  // Добавляем свойству мутатор.

                    properties.Add(propertyName, propertyValue);                                                                                        // Сохраняем значения в словарь для дальнейшей передачи свойствам значений.
                }

                // Перебираем все поля нашего типа.
                foreach (FieldInfo fieldInfo in sourceType.GetFields())
                {
                    AmfMemberAttribute attribute = fieldInfo.GetAttribute <AmfMemberAttribute>();  // Получаем наш кастомный атрибут типа AmfMemberAttribute.

                    if (attribute == null)
                    {
                        continue;                                         // Если атрибут не указан - пропускаем поле.
                    }
                    string fieldName  = attribute.Name ?? fieldInfo.Name; // Получаем имя поля.
                    object fieldValue = fieldInfo.GetValue(sourceObject); // Получаем значение поля.
                    Type   fieldType  = fieldInfo.FieldType;              // Получаем метаданные типа поля.

                    // Если у типа задан атрибут или это словарь...
                    if (fieldInfo.FieldType.IsDefinedAttribute <AmfObjectAttribute>() || fieldType.IsDictionary())
                    {
                        // Генерируем объект типа, заданного в атрибуте.
                        fieldValue = fieldType.IsDictionary()
                            ? GenerateType(fieldValue as IEnumerable <KeyValuePair <string, object> >)
                            : GenerateType(fieldValue);

                        fieldType = fieldValue.GetType();   // Обновляем тип поля.
                    }

                    typeBuilder.DefineField(fieldName, fieldType, FieldAttributes.Public); // Определяем новое поле.
                    fields.Add(fieldName, fieldValue);                                     // Сохраняем значения в словарь для дальнейшей передачи свойствам значений.
                }
            }
            else
            {
                // Перебираем все свойства нашего типа.
                foreach (PropertyInfo propertyInfo in sourceType.GetProperties())
                {
                    AmfMemberAttribute attribute = propertyInfo.GetAttribute <AmfMemberAttribute>();  // Получаем наш кастомный атрибут типа AmfMemberAttribute.

                    if (attribute == null)
                    {
                        continue;                                                                                         // Если атрибут не указан - пропускаем свойство.
                    }
                    string propertyName  = attribute.Name ?? propertyInfo.Name;                                           // Получаем имя свойства.
                    object propertyValue = propertyInfo.GetValue(sourceObject, null);                                     // Получаем значение свойства.
                    Type   propertyType  = propertyInfo.PropertyType;                                                     // Получаем метаданные типа свойства.

                    AmfObjectAttribute propertyAttribute = propertyInfo.PropertyType.GetAttribute <AmfObjectAttribute>(); // Получаем атрибут у свойства.

                    // Если у типа задан атрибут или это словарь...
                    if (propertyAttribute != null || propertyType.IsDictionary())
                    {
                        // Генерируем объект типа, заданного в атрибуте.
                        propertyValue = propertyType.IsDictionary()
                            ? GenerateType(propertyValue as IEnumerable <KeyValuePair <string, object> >)
                            : GenerateType(propertyValue);

                        propertyType = propertyValue.GetType();   // Обновляем тип свойства.
                    }

                    properties.Add(propertyName, propertyValue);  // Сохраняем значения в словарь для дальнейшей передачи свойствам значений.
                }

                // Перебираем все поля нашего типа.
                foreach (FieldInfo fieldInfo in sourceType.GetFields())
                {
                    AmfMemberAttribute attribute = fieldInfo.GetAttribute <AmfMemberAttribute>();  // Получаем наш кастомный атрибут типа AmfMemberAttribute.

                    if (attribute == null)
                    {
                        continue;                                                                                // Если атрибут не указан - пропускаем поле.
                    }
                    string fieldName  = attribute.Name ?? fieldInfo.Name;                                        // Получаем имя поля.
                    object fieldValue = fieldInfo.GetValue(sourceObject);                                        // Получаем значение поля.
                    Type   fieldType  = fieldInfo.FieldType;                                                     // Получаем метаданные типа поля.

                    AmfObjectAttribute fieldAttribute = fieldInfo.FieldType.GetAttribute <AmfObjectAttribute>(); // Получаем атрибут у поля.

                    // Если у типа задан атрибут или это словарь...
                    if (fieldAttribute != null || fieldType.IsDictionary())
                    {
                        // Генерируем объект типа, заданного в атрибуте.
                        fieldValue = fieldType.IsDictionary()
                            ? GenerateType(fieldValue as IEnumerable <KeyValuePair <string, object> >)
                            : GenerateType(fieldValue);

                        fieldType = fieldValue.GetType();   // Обновляем тип поля.
                    }

                    fields.Add(fieldName, fieldValue);  // Сохраняем значения в словарь для дальнейшей передачи свойствам значений.
                }
            }

            object targetObject = Activator.CreateInstance(definedType ?? typeBuilder.CreateType());  // Создаём инстанс нашего динамического типа.

            // Раставляем значения всем свойствам объекта.
            foreach (KeyValuePair <string, object> property in properties)
            {
                targetObject.GetType().GetProperty(property.Key).SetValue(targetObject, property.Value, null);
            }

            // Раставляем значения всем полям объекта.
            foreach (KeyValuePair <string, object> field in fields)
            {
                targetObject.GetType().GetField(field.Key).SetValue(targetObject, field.Value);
            }

            return(targetObject);
        }
示例#2
0
        /// <summary>
        /// Десериализует буфер данных в объект AMF.
        /// </summary>
        /// <typeparam name="T">Тип десериализуемого объекта.</typeparam>
        /// <param name="sourceBuffer">Исходный буфер данных объекта.</param>
        /// <returns></returns>
        public static T DeserializeFromAmf <T>(this byte[] sourceBuffer) where T : class
        {
            using (MemoryStream memoryStream = new MemoryStream(sourceBuffer))              // Открываем поток для чтения данных из буфера.
                using (AMFDeserializer amfDeserializer = new AMFDeserializer(memoryStream)) // Инициализируем десериализатор для AMF.
                {
                    AMFMessage amfMessage = amfDeserializer.ReadAMFMessage();               // Получем сообщение AMF.
                    AMFBody    amfBody    = amfMessage.GetBodyAt(0);                        // Получаем body из сообщения AMF.

                    object amfObject     = amfBody.Content;                                 // Получаем объект из body AMF.
                    Type   amfObjectType = amfObject.GetType();                             // Получаем метаданные типа объекта AMF.

                    // Формируем запрос на получение всей коллекции нужных нам типов с заданными атрибутами.
                    IEnumerable <Type> types = from type in Assembly.GetExecutingAssembly().GetTypes()
                                               where Attribute.IsDefined(type, typeof(AmfObjectAttribute))
                                               select type;

                    Type currentType = null; // Определяем текущий тип объекта из нашей сборки.

                    // Проходим по всем найденным типам с нашим атрибутом.
                    foreach (Type type in types)
                    {
                        AmfObjectAttribute attribute = type.GetAttribute <AmfObjectAttribute>(); // Получаем наш атрибут.

                        if (attribute == null || attribute.Name != amfObjectType.FullName)
                        {
                            continue;       // Если в атрибуте задано другое имя - пропускаем итерацию.
                        }
                        currentType = type; // Иначе сохраняем текущий тип объекта.
                        break;
                    }

                    if (currentType == null)
                    {
                        return(default(T));                                      // Если тип не найден - возвращаем null.
                    }
                    object targetObject = Activator.CreateInstance(currentType); // Создаём инстанс нашего типа.

                    // Анализируем все свойства нашего класса.
                    foreach (PropertyInfo propertyInfo in currentType.GetProperties())
                    {
                        AmfMemberAttribute attribute = propertyInfo.GetAttribute <AmfMemberAttribute>(); // Получаем наш кастомный атрибут.

                        if (attribute == null)
                        {
                            continue;                                                                                                   // Если атрибут не задан - пропускаем.
                        }
                        propertyInfo.SetValue(targetObject, amfObjectType.GetProperty(attribute.Name).GetValue(amfObject, null), null); // Получаем значение свойства у десериализуемого объекта и сохраняем его в свойстве нашего объекта.
                    }

                    // Анализируем все поля нашего класса.
                    foreach (FieldInfo fieldInfo in currentType.GetFields())
                    {
                        AmfMemberAttribute attribute = fieldInfo.GetAttribute <AmfMemberAttribute>(); // Получаем наш кастомный атрибут.

                        if (attribute == null)
                        {
                            continue;                                                                                 // Если атрибут не задан - пропускаем.
                        }
                        fieldInfo.SetValue(targetObject, amfObjectType.GetField(attribute.Name).GetValue(amfObject)); // Получаем значение поля у десериализуемого объекта и сохраняем его в поле нашего объекта.
                    }

                    return(targetObject as T); // Приводит к типу T и возвращает текущий объект.
                }
        }