Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using Microsoft.Xna.Framework;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Reflection;
- using System.Text;
- using System.Runtime.Serialization;
- using System.ComponentModel;
- namespace DownUnder.Content.Utilities.Serialization
- {
- static class CSCreator
- {
- // SerializeToCS is something I came up with wanting the ability to
- // serialize something to an entirely new object, usable without
- // saving or loading, accessible directly through Visual Studio.
- // Typically, if you were to save an object's state to the disk,
- // you would use XmlSerializer. You would only have to remember the
- // name of the object, and the location.
- /// <summary>
- /// This will take a given object and return a C# class file that generates it.
- /// </summary>
- /// <param name="obj"></param>
- /// <returns></returns>
- public static String SerializeToCS<T>(T obj, String object_name, String namespace_ = "DownUnder.Content.Utilities")
- {
- Debug.WriteLine("ObjectSerializer start");
- // Dependencies
- List<String> dependencies = new List<string>();
- AddNamespace("DownUnder.Content.Utilities", ref dependencies);
- AddNamespace("System.Collections.Generic", ref dependencies);
- AddNamespace(typeof(T).Namespace, ref dependencies);
- string comment = "// Sections of this code are autogenerated, changes made to sections \n// between /*GeneratedCodeStart*/ and /*GeneratedCodeEnd*/ will\n// not be preserved if the object is editted in DownUnder.UIEditor.";
- String namespace_start = "namespace " + namespace_ + "\n{\n";
- String class_start = $"public class {object_name} : {typeof(T).Name} \n{{\n";
- String fields_string = CreateFields(obj, ref dependencies);
- String constructors_string = CreateConstructors<T>(object_name, ref dependencies, "CSCreatorInitializeFields();");
- string initialize_function = "void CSCreatorInitializeFields()\n{\n" + fields_string + "\n}\n";
- String class_end = "\n}\n";
- String namespace_end = "}";
- String dependencies_string = StringManipulation.StringListToString(dependencies);
- StringBuilder code = new StringBuilder($"{comment}\n\n{dependencies_string}\n{namespace_start}{class_start}{constructors_string}\n{initialize_function}{class_end}{namespace_end}");
- StringManipulation.IndentCSCode(ref code);
- Debug.WriteLine(code);
- return code.ToString();
- }
- // todo: check to see if object has empty constructor
- static String CreateConstructors<T>(String object_name, ref List<String> dependencies, String code = "")
- {
- List<String> constructors = new List<string>();
- StringBuilder parameters = new StringBuilder();
- StringBuilder parameters_valuenames_only = new StringBuilder();
- foreach (var constructor in typeof(T).GetConstructors())
- {
- parameters.Clear();
- parameters_valuenames_only.Clear();
- foreach (var parameter in constructor.GetParameters().ToList())
- {
- AddNamespace(parameter.ParameterType.Namespace, ref dependencies);
- parameters.Append($"{parameter.ParameterType.Name} {parameter.Name},");
- parameters_valuenames_only.Append($"{parameter.Name},");
- }
- StringManipulation.TrimEnd(ref parameters, ',');
- StringManipulation.TrimEnd(ref parameters_valuenames_only, ',');
- constructors.Add($"public {object_name}({parameters}) : base({parameters_valuenames_only}) {{{code}}}");
- }
- return StringManipulation.StringListToString(constructors);
- }
- // field1 = 6;
- // field2 = new Object(){ something = something };
- // field3 = ...;
- public static String CreateFields(object obj, ref List<String> dependencies, bool brackets = false)
- {
- StringBuilder field_string = new StringBuilder();
- string definition = "";
- char separating_char = ';';
- if (brackets) separating_char = ',';
- foreach (FieldInfo field in obj.GetType().GetFields())
- {
- if (field.IsNotSerialized) continue; // skip if field has the [NonSerialized] attribute.
- object value = field.GetValue(obj);
- if (value == null) { definition = "null"; }
- else { definition = CreateDefinition(value, ref dependencies); }
- field_string.AppendLine($"{field.Name} = {definition}{separating_char}");
- }
- foreach (PropertyInfo property in obj.GetType().GetProperties())
- {
- if (property.GetSetMethod() == null) { continue; } // Skip if there is no set; method
- object value = property.GetValue(obj);
- // This is a standard that probably won't be followed.
- // implementing a check for [DataMember] would result
- // in more accurate behavior.
- //if (!value.GetType().GetCustomAttributes(typeof(SerializableAttribute), true).Any()) { continue; } // Skip if property isn't marked as serializable
- if (value == null) { definition = "null"; }
- else { definition = CreateDefinition(value, ref dependencies); }
- field_string.AppendLine($"{property.Name} = {definition}{separating_char}");
- }
- if (!brackets) return field_string.ToString().TrimEnd(',');
- return "\n{\n" + field_string.ToString().TrimEnd(',') + "\n}\n";
- }
- // new Object(){ field = definition, second_field = 0f, ... }
- public static String CreateDefinition(object value, ref List<String> dependencies)
- {
- Type field_type = value.GetType();
- // the following is a psuedo switch statement. Switch based on what type 'value' is.
- if (field_type.Name == "String") { return $"\"{StringManipulation.InsertLiterals(value.ToString())}\""; }
- else if (field_type.Name == "Char") { return $"'{StringManipulation.InsertLiterals(value.ToString())}'"; }
- else if (value.GetType().BaseType.Name == "ValueType") // Handle basic C# types
- {
- if (Utility.IsFloat((ValueType)value))
- {
- return value.ToString() + "f";
- }
- else if (Utility.IsNumeric((ValueType)value))
- {
- return value.ToString();
- }
- // Check to see if the object uses DataContractAttribute, in which case the 'Deconstruct' method must be used to properly serialize the object.
- else if (value.GetType().GetCustomAttributes(typeof(DataContractAttribute), true).Any())
- {
- return CreateNewStatement(value, ref dependencies) + CreateFields(value, ref dependencies, true); ;
- }
- else switch (value.GetType().Name)
- {
- case "Boolean": return value.ToString().ToLower();
- default:
- return CreateNewStatement(value, ref dependencies) + CreateFields(value, ref dependencies, true);
- }
- }
- // Handle List/Array (recursively)
- else if ((value.GetType().Name + " ").Substring(0, 5) == "List`" || value.GetType().IsArray)
- { // add the spaces so substr doesn't throw an error.
- string list_definition = "";
- foreach (var obj in (IList)value)
- {
- list_definition += CreateDefinition(obj, ref dependencies) + ',';
- }
- return CreateNewStatement(value, ref dependencies) + "{" + list_definition.TrimEnd(',') + "}";
- }
- else if (value.GetType().IsEnum)
- { // Enums
- AddNamespace(value.GetType().Namespace, ref dependencies);
- return value.GetType().Name + '.' + value.ToString();
- }
- return CreateNewStatement(value, ref dependencies) + CreateFields(value, ref dependencies, true);
- }
- // new Object()
- static String CreateNewStatement(object value, ref List<String> dependencies, string parameters = "")
- {
- string type_name = value.GetType().Name;
- if (type_name.Contains('`')) // GenericArguments Name has a `x flag at the end representing how many generic arguments there are. Remove that here.
- {
- type_name = type_name.Substring(0, type_name.IndexOf('`'));
- }
- string generic_arguments = "";
- foreach (Type generic_argument in value.GetType().GetGenericArguments())
- {
- if (generic_arguments != "") { generic_arguments += ','; }
- generic_arguments += generic_argument.Name;
- AddNamespace(generic_argument.Namespace, ref dependencies);
- }
- if (generic_arguments != "") generic_arguments = '<' + generic_arguments + '>';
- AddNamespace(value.GetType().Namespace, ref dependencies);
- string parenthesis = "(" + parameters + ")";
- if (value.GetType().IsArray) Debug.WriteLine(parenthesis = "");
- return "new " + type_name + generic_arguments + parenthesis;
- }
- /// <summary>
- /// Adds the dependency to the passed list if it doesn't already exist.
- /// </summary>
- /// <param name="dependency"></param>
- /// <param name="dependencies"></param>
- static void AddNamespace(String dependency, ref List<String> dependencies)
- {
- dependency = $"using {dependency};";
- if (dependencies.Contains(dependency)) return;
- dependencies.Add(dependency);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement