Advertisement
jamieyello

CSCreator

Oct 4th, 2018
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.24 KB | None | 0 0
  1. using Microsoft.Xna.Framework;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Text;
  9. using System.Runtime.Serialization;
  10. using System.ComponentModel;
  11.  
  12. namespace DownUnder.Content.Utilities.Serialization
  13. {
  14.     static class CSCreator
  15.     {
  16.         // SerializeToCS is something I came up with wanting the ability to
  17.         // serialize something to an entirely new object, usable without
  18.         // saving or loading, accessible directly through Visual Studio.
  19.  
  20.         // Typically, if you were to save an object's state to the disk,
  21.         // you would use XmlSerializer. You would only have to remember the
  22.         // name of the object, and the location.
  23.  
  24.         /// <summary>
  25.         /// This will take a given object and return a C# class file that generates it.
  26.         /// </summary>
  27.         /// <param name="obj"></param>
  28.         /// <returns></returns>
  29.         public static String SerializeToCS<T>(T obj, String object_name, String namespace_ = "DownUnder.Content.Utilities")
  30.         {
  31.             Debug.WriteLine("ObjectSerializer start");
  32.  
  33.             // Dependencies
  34.             List<String> dependencies = new List<string>();
  35.             AddNamespace("DownUnder.Content.Utilities", ref dependencies);
  36.             AddNamespace("System.Collections.Generic", ref dependencies);
  37.             AddNamespace(typeof(T).Namespace, ref dependencies);
  38.  
  39.             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.";
  40.            
  41.             String namespace_start = "namespace " + namespace_ + "\n{\n";
  42.             String class_start = $"public class {object_name} : {typeof(T).Name} \n{{\n";
  43.             String fields_string = CreateFields(obj, ref dependencies);
  44.             String constructors_string = CreateConstructors<T>(object_name, ref dependencies, "CSCreatorInitializeFields();");
  45.             string initialize_function = "void CSCreatorInitializeFields()\n{\n" + fields_string + "\n}\n";
  46.             String class_end = "\n}\n";
  47.             String namespace_end = "}";
  48.             String dependencies_string = StringManipulation.StringListToString(dependencies);
  49.             StringBuilder code = new StringBuilder($"{comment}\n\n{dependencies_string}\n{namespace_start}{class_start}{constructors_string}\n{initialize_function}{class_end}{namespace_end}");
  50.             StringManipulation.IndentCSCode(ref code);
  51.  
  52.             Debug.WriteLine(code);
  53.             return code.ToString();
  54.         }
  55.  
  56.         // todo: check to see if object has empty constructor
  57.         static String CreateConstructors<T>(String object_name, ref List<String> dependencies, String code = "")
  58.         {
  59.             List<String> constructors = new List<string>();
  60.             StringBuilder parameters = new StringBuilder();
  61.             StringBuilder parameters_valuenames_only = new StringBuilder();
  62.             foreach (var constructor in typeof(T).GetConstructors())
  63.             {
  64.                 parameters.Clear();
  65.                 parameters_valuenames_only.Clear();
  66.                 foreach (var parameter in constructor.GetParameters().ToList())
  67.                 {
  68.                     AddNamespace(parameter.ParameterType.Namespace, ref dependencies);
  69.                     parameters.Append($"{parameter.ParameterType.Name} {parameter.Name},");
  70.                     parameters_valuenames_only.Append($"{parameter.Name},");
  71.                 }
  72.                 StringManipulation.TrimEnd(ref parameters, ',');
  73.                 StringManipulation.TrimEnd(ref parameters_valuenames_only, ',');
  74.  
  75.                 constructors.Add($"public {object_name}({parameters}) : base({parameters_valuenames_only}) {{{code}}}");
  76.             }
  77.             return StringManipulation.StringListToString(constructors);
  78.         }
  79.        
  80.         // field1 = 6;
  81.         // field2 = new Object(){ something = something };
  82.         // field3 = ...;
  83.         public static String CreateFields(object obj, ref List<String> dependencies, bool brackets = false)
  84.         {
  85.             StringBuilder field_string = new StringBuilder();
  86.             string definition = "";
  87.             char separating_char = ';';
  88.             if (brackets) separating_char = ',';
  89.  
  90.             foreach (FieldInfo field in obj.GetType().GetFields())
  91.             {
  92.                 if (field.IsNotSerialized) continue; // skip if field has the [NonSerialized] attribute.
  93.                 object value = field.GetValue(obj);
  94.  
  95.                 if (value == null) { definition = "null"; }
  96.                 else { definition = CreateDefinition(value, ref dependencies); }
  97.                
  98.                 field_string.AppendLine($"{field.Name} = {definition}{separating_char}");
  99.             }
  100.  
  101.             foreach (PropertyInfo property in obj.GetType().GetProperties())
  102.             {
  103.                 if (property.GetSetMethod() == null) { continue; } // Skip if there is no set; method
  104.                 object value = property.GetValue(obj);
  105.  
  106.                 // This is a standard that probably won't be followed.
  107.                 // implementing a check for [DataMember] would result
  108.                 // in more accurate behavior.
  109.                 //if (!value.GetType().GetCustomAttributes(typeof(SerializableAttribute), true).Any()) { continue; } // Skip if property isn't marked as serializable
  110.  
  111.                 if (value == null) { definition = "null"; }
  112.                 else { definition = CreateDefinition(value, ref dependencies); }
  113.  
  114.                 field_string.AppendLine($"{property.Name} = {definition}{separating_char}");
  115.             }
  116.  
  117.             if (!brackets) return field_string.ToString().TrimEnd(',');
  118.             return "\n{\n" + field_string.ToString().TrimEnd(',') + "\n}\n";
  119.         }
  120.  
  121.         // new Object(){ field = definition, second_field = 0f, ... }
  122.         public static String CreateDefinition(object value, ref List<String> dependencies)
  123.         {
  124.             Type field_type = value.GetType();
  125.             // the following is a psuedo switch statement. Switch based on what type 'value' is.
  126.             if (field_type.Name == "String") { return $"\"{StringManipulation.InsertLiterals(value.ToString())}\""; }
  127.             else if (field_type.Name == "Char") { return $"'{StringManipulation.InsertLiterals(value.ToString())}'"; }
  128.             else if (value.GetType().BaseType.Name == "ValueType") // Handle basic C# types
  129.             {
  130.                 if (Utility.IsFloat((ValueType)value))
  131.                 {
  132.                     return value.ToString() + "f";
  133.                 }
  134.                 else if (Utility.IsNumeric((ValueType)value))
  135.                 {
  136.                     return value.ToString();
  137.                 }            
  138.                 // Check to see if the object uses DataContractAttribute, in which case the 'Deconstruct' method must be used to properly serialize the object.
  139.                 else if (value.GetType().GetCustomAttributes(typeof(DataContractAttribute), true).Any())
  140.                 {
  141.                     return CreateNewStatement(value, ref dependencies) + CreateFields(value, ref dependencies, true); ;
  142.                 }
  143.                 else switch (value.GetType().Name)
  144.                     {
  145.                         case "Boolean": return value.ToString().ToLower();
  146.                         default:
  147.                             return CreateNewStatement(value, ref dependencies) + CreateFields(value, ref dependencies, true);
  148.                     }
  149.                
  150.             }
  151.             // Handle List/Array (recursively)
  152.             else if ((value.GetType().Name + "     ").Substring(0, 5) == "List`" || value.GetType().IsArray)
  153.             { // add the spaces so substr doesn't throw an error.
  154.                 string list_definition = "";
  155.                 foreach (var obj in (IList)value)
  156.                 {
  157.                     list_definition += CreateDefinition(obj, ref dependencies) + ',';
  158.                 }
  159.                 return CreateNewStatement(value, ref dependencies) + "{" + list_definition.TrimEnd(',') + "}";
  160.             }
  161.             else if (value.GetType().IsEnum)
  162.             { // Enums
  163.                 AddNamespace(value.GetType().Namespace, ref dependencies);
  164.                 return value.GetType().Name + '.' + value.ToString();
  165.             }
  166.  
  167.             return CreateNewStatement(value, ref dependencies) + CreateFields(value, ref dependencies, true);
  168.         }
  169.  
  170.         // new Object()
  171.         static String CreateNewStatement(object value, ref List<String> dependencies, string parameters = "")
  172.         {
  173.             string type_name = value.GetType().Name;
  174.             if (type_name.Contains('`')) // GenericArguments Name has a `x flag at the end representing how many generic arguments there are. Remove that here.
  175.             {
  176.                 type_name = type_name.Substring(0, type_name.IndexOf('`'));
  177.             }
  178.            
  179.             string generic_arguments = "";
  180.             foreach (Type generic_argument in value.GetType().GetGenericArguments())
  181.             {
  182.                 if (generic_arguments != "") { generic_arguments += ','; }
  183.                 generic_arguments += generic_argument.Name;
  184.                 AddNamespace(generic_argument.Namespace, ref dependencies);
  185.             }
  186.             if (generic_arguments != "") generic_arguments = '<' + generic_arguments + '>';
  187.  
  188.             AddNamespace(value.GetType().Namespace, ref dependencies);
  189.  
  190.             string parenthesis = "(" + parameters + ")";
  191.             if (value.GetType().IsArray) Debug.WriteLine(parenthesis = "");
  192.             return "new " + type_name + generic_arguments + parenthesis;
  193.         }
  194.        
  195.         /// <summary>
  196.         /// Adds the dependency to the passed list if it doesn't already exist.
  197.         /// </summary>
  198.         /// <param name="dependency"></param>
  199.         /// <param name="dependencies"></param>
  200.         static void AddNamespace(String dependency, ref List<String> dependencies)
  201.         {
  202.             dependency = $"using {dependency};";
  203.             if (dependencies.Contains(dependency)) return;
  204.             dependencies.Add(dependency);
  205.         }
  206.     }
  207. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement