/// <summary> /// AMF. /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] public class AmfObjectAttribute : Attribute { /// <summary> /// . /// </summary> public string Name { get; set; } /// <summary> /// <see cref="AmfObjectAttribute"/>. /// </summary> /// <param name="name"> .</param> public AmfObjectAttribute(string name) { Name = name; } /// <summary> /// <see cref="AmfObjectAttribute"/>. /// </summary> public AmfObjectAttribute() : this(null) { } }
/// <summary> /// AMF. /// </summary> [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public class AmfMemberAttribute : Attribute { /// <summary> /// . /// </summary> public string Name { get; set; } /// <summary> /// <see cref="AmfMemberAttribute"/>. /// </summary> /// <param name="name"> .</param> public AmfMemberAttribute(string name) { Name = name; } /// <summary> /// <see cref="AmfMemberAttribute"/>. /// </summary> public AmfMemberAttribute() : this(null) { } }
/// <summary> /// AMF- . "namespase.of.your.object". /// </summary> [AmfObject("namespase.of.your.object")] public class CustomAmfObject { /// <summary> /// <see cref="bool"/>. "bit_prop". /// </summary> [AmfMember("bit_prop")] public bool BooleanProperty { get; set; } = true; /// <summary> /// <see cref="sbyte"/>. UnsignedByteProperty. /// </summary> [AmfMember] public sbyte UnsignedByteProperty { get; set; } = 2; /// <summary> /// <see cref="string"/>. . /// </summary> public string StringProperty { get; set; } = "test"; /// <summary> /// <see cref="bool"/>. "bit_fld". /// </summary> [AmfMember("bit_fld")] public bool booleanField = false; /// <summary> /// <see cref="float"/>. singleField. /// </summary> [AmfMember] public float singleField = -5.00065f; /// <summary> /// <see cref="string"/>. . /// </summary> public string stringField = "test2"; /// <summary> /// <see cref="CustomAmfObject"/>. /// </summary> public CustomAmfObject() { } }
/// <summary> /// / AMF. /// </summary> public static class Extensions { }
/// <summary> /// . /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="sourceType"> .</param> /// <returns></returns> private static T GetAttribute<T>(this Type sourceType) where T : Attribute { object[] attributes = sourceType.GetCustomAttributes(typeof(T), true); // . if (attributes == null || attributes.Length == 0) return default(T); // - null. return attributes[0] as T; } /// <summary> /// . /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="sourceMember"> .</param> /// <returns></returns> private static T GetAttribute<T>(this MemberInfo sourceMember) where T : Attribute { object[] attributes = sourceMember.GetCustomAttributes(typeof(T), true); // . if (attributes == null || attributes.Length == 0) return default(T); // - null. return attributes[0] as T; } /// <summary> /// , . /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="sourceType"> .</param> /// <returns></returns> private static bool IsDefinedAttribute<T>(this Type sourceType) { object[] attributes = sourceType.GetCustomAttributes(typeof(T), true); // . return attributes != null && attributes.Length > 0; }
/// <summary> /// . /// </summary> private static ModuleBuilder moduleBuilder; /// <summary> /// <see cref="Extensions"/>. /// </summary> static Extensions() { AssemblyName assemblyName = new AssemblyName("AmfDynamicAssembly"); // . AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); // . moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll"); // . }
TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
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); // .
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); // .
object targetObject = Activator.CreateInstance(typeBuilder.CreateType());
/// <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; }
/// <summary> /// <see cref="AmfObjectAttribute"/>, , <see cref="AmfMemberAttribute"/>. /// </summary> /// <param name="sourceObjects"> .</param> /// <returns></returns> private static object[] GenerateType(object[] sourceObjects) { for (int i = 0; i < sourceObjects.Length; i++) sourceObjects[i] = GenerateType(sourceObjects[i]); // . return sourceObjects; }
/// <summary> /// , . , object, , AMF. /// </summary> /// <param name="sourceType"> .</param> /// <returns></returns> private static bool IsDictionary(this Type sourceType) { Type type0 = typeof(IEnumerable<KeyValuePair<string, object>>); Type type1 = typeof(IDictionary<string, object>); Type type2 = typeof(Dictionary<string, object>); return sourceType.FullName == type0.FullName || sourceType.IsSubclassOf(type0) || sourceType.FullName == type1.FullName || sourceType.IsSubclassOf(type1) || sourceType.FullName == type2.FullName || sourceType.IsSubclassOf(type2); } /// <summary> /// "-", , - . /// </summary> /// <param name="fields"> "-"</param> /// <returns></returns> private static object GenerateType(IEnumerable<KeyValuePair<string, object>> fields) { AssemblyName assemblyName = new AssemblyName("AmfDynamicAssemblyForDictionary"); // . AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); // . ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll"); // . TypeBuilder typeBuilder = moduleBuilder.DefineType(typeof(Array).FullName, 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 (KeyValuePair<string, object> pair in fields) { object fieldValue = pair.Value; // . Type fieldType = fieldValue.GetType(); // . // ... if (fieldType.IsDefinedAttribute<AmfObjectAttribute>()) { fieldValue = GenerateType(fieldValue); // , . fieldType = fieldValue.GetType(); // . } typeBuilder.DefineField(pair.Key, fieldType, FieldAttributes.Public); // . } object targetObject = Activator.CreateInstance(typeBuilder.CreateType()); // . // . foreach (KeyValuePair<string, object> pair in fields) targetObject.GetType().GetField(pair.Key).SetValue(targetObject, pair.Value); return targetObject; }
/// <summary> /// AMF. /// </summary> /// <param name="sourceObject"> .</param> /// <param name="version"> AMF.</param> /// <returns></returns> public static byte[] SerializeToAmf(this object sourceObject, ushort version) { using (MemoryStream memoryStream = new MemoryStream()) // . using (AMFSerializer amfSerializer = new AMFSerializer(memoryStream)) // AMF. { AMFMessage amfMessage = new AMFMessage(version); // AMF. AMFBody amfBody = new AMFBody(AMFBody.OnResult, null, GenerateType(sourceObject)); // AMF. amfMessage.AddBody(amfBody); // body AMF. amfSerializer.WriteMessage(amfMessage); // . return memoryStream.ToArray(); // . } } /// <summary> /// AMF3. /// </summary> /// <param name="sourceObject"> .</param> /// <returns></returns> public static byte[] SerializeToAmf(this object sourceObject) => sourceObject.SerializeToAmf(3); /// <summary> /// *.amf. /// </summary> /// <param name="sourceObject"> .</param> /// <param name="path"> .</param> /// <param name="version"> AMF.</param> public static void SerializeToAmf(this object sourceObject, string path, ushort version) => File.WriteAllBytes($"{path}.amf", sourceObject.SerializeToAmf(version)); /// <summary> /// *.amf. AMF 3. /// </summary> /// <param name="sourceObject"> .</param> /// <param name="path"> .</param> public static void SerializeToAmf(this object sourceObject, string path) => sourceObject.SerializeToAmf(path, 3);
/// <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 . } } /// <summary> /// *.amf. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="obj"> .</param> /// <param name="path"> .</param> /// <returns> AMF.</returns> public static T DeserializeFromAmf<T>(this object obj, string path) where T : class => File.ReadAllBytes($"{path}.amf").DeserializeFromAmf<T>();
using (MemoryStream memoryStream = new MemoryStream()) // . using (AMFWriter amfWriter = new AMFWriter(memoryStream)) // AMF. using (WebClient client = new WebClient()) // HTTP- ( HttpWebRequest). { amfWriter.WriteBytes(new CustomAmfObject().SerializeToAmf()); // . client.Headers[HttpRequestHeader.ContentType] = "application/x-amf"; // ContentType . byte[] buffer = client.UploadData(Host, "POST", memoryStream.ToArray()); // . }
[AmfObject("example.game.gameObject")] public class CustomAmfObject : IExternalizable { [AmfMember("x")] public float X { get; set; } [AmfMember("y")] public float Y { get; set; } [AmfMember("z")] public float Z { get; set; } public CustomAmfObject(float x, float y, float z) { X = x; Y = y; Z = z; } public CustomAmfObject() : this(0f, 0f, 0f) { } public void ReadExternal(IDataInput input) { X = input.ReadFloat(); Y = input.ReadFloat(); Z = input.ReadFloat(); } public void WriteExternal(IDataOutput output) { output.WriteFloat(X); output.WriteFloat(Y); output.WriteFloat(Z); } }
Source: https://habr.com/ru/post/320446/
All Articles