- Home /
Editorscript: Generate enum from string[]
I'm wondering if it's possible to Generate an enum in an Editorscript?
I have a method in an Editorscript that dynamically creates a string[]. Let's say holds the strings "Foo", "Goo" and "Hoo". Is it possible, from that array, to generate an enum, like the following:
public enum MyEnum
{
Foo,
Goo,
Hoo
}
I guess Unity will have to recompile after that. When recompiling is done, the enum should be ready to be used in PlayMode.
Is that by any means possible? Any input is most welcome :-)
Answer by DustyScreen · May 10, 2016 at 10:11 AM
Though @TimHeijden's code works like a charm (and got me in the right direction) I ended up doing it like this:
#if UNITY_EDITOR
using UnityEditor;
using System.IO;
public class GenerateEnum
{
[MenuItem( "Tools/GenerateEnum" )]
public static void Go()
{
string enumName = "MyEnum";
string[] enumEntries = { "Foo", "Goo", "Hoo" };
string filePathAndName = "Assets/Scripts/Enums/" + enumName + ".cs"; //The folder Scripts/Enums/ is expected to exist
using ( StreamWriter streamWriter = new StreamWriter( filePathAndName ) )
{
streamWriter.WriteLine( "public enum " + enumName );
streamWriter.WriteLine( "{" );
for( int i = 0; i < enumEntries.Length; i++ )
{
streamWriter.WriteLine( "\t" + enumEntries[i] + "," );
}
streamWriter.WriteLine( "}" );
}
AssetDatabase.Refresh();
}
}
#endif
Do you get autocompletion on the created Enum in visual studio with this ?
Answer by TimHeijden · Apr 13, 2016 at 10:15 PM
It's actually quite simple if you want to do this in an editor script. Like any text file, you can use a StringBuilder to create the contents:
string enumNam = "MyEnum";
string[] enumEntries = new string[] { "Foo", "Goo", "Hoo" };
StringBuilder str = new StringBuilder();
str.AppendFormat(@"public enum {0}\n{\n", enumName);
for (int i = 0; i < enumEntries.Length; i++)
{
str.AppendFormat(@"{0},\n", enumEntries[i]);
}
str.AppendLine(@"}");
Then, use some UnityEditor classes to get the asset path. For example:
string path = AssetDatabase.GetAssetPath(serializedObject.targetObject);
path = path.Substring(0, path.Length - Path.GetExtension(path).Length) + ".cs";
File.WriteAllText(path, str.ToString());
AssetDatabase.ImportAsset(path);
And that should be it! (note: depending on what kind of editor script you want to write, you may need to use a different way to get the paths, but there are loads of ways to that easily found with google.
Answer by lclemens · Jul 10, 2021 at 12:37 AM
Another thing you may want to do is ensure the strings don't contain any invalid characters or keywords that would break in C#. So you can combine some of the other answers here with something like this:
private static HashSet<string> csharpKeywords = new HashSet<string> {
"abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked",
"class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else",
"enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for",
"foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock",
"long", "namespace", "new", "null", "object", "operator", "out", "override", "params",
"private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed",
"short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw",
"true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using",
"virtual", "void", "volatile", "while"
};
// given a string, attempts to make the string compatible with an enum
static string MakeStringEnumCompatible(string text)
{
if (text.Length <= 0) { return "INVALID_ENUM_NAME"; }
string ret = "";
// first char must be a letter or an underscore
if (char.IsLetter(text[0]) || (text[0] == '_')) { ret += text[0]; }
// strip out anything that's not a digit or underscore
for (int i = 1; i < text.Length; ++i) {
if (char.IsLetterOrDigit(text[i]) || (text[i] == '_')) { ret += text[i]; }
}
if (ret.Length <= 0) { return "INVALID_ENUM_NAME"; }
// all the keywords are lowercase, so if we just change the first letter to uppercase,
// then there will be no conflict
if (csharpKeywords.Contains(ret)) { ret = char.ToUpper(ret[0]) + ret.Substring(1); }
return ret;
}
Your answer
Follow this Question
Related Questions
How to create enum out of array of string? 2 Answers
Limiting options in Unity Editor enum popup box based on prior selection 0 Answers
Problem with second enum selection inspector 0 Answers
How to create bitmask flags per scene that are available in the editor? 0 Answers
UIElements EnumField data binding 0 Answers