0

I want to create a new class at runtime, get the type, and create a List of that type. For example:

    void CreateNewClass(string name)
    {
        File file = CreateFile(name);
        Type type = GetTypeOfFile(file);

        List<type> someList = new List<type>();
    }

    
    void CreateFile(string name)
    {
        //Get a template file
        //copy that file
        //change some names and stuff in it
        //return the file
    }

    Type GetTypeOfFile(File file)
    {
        //get the class(type) of that file
        // return type
    }

I do not want to generate that class in memory, I need to have that class as a file. The file creation is not a problem.

I just need to know:

  • How to load the file/class and get it's type
  • How to create a list with the loaded type

I guess something with Reflections need to happen, but after that I'm clueless.


edit:

FYI: I don't actually want to create a List, I need this functionallity for a Unity Project. For those who are familiar with it: I want to create ScriptableObjects (the class itself and the asset) with one button click. So I have a base class like:

public abstract class State : ScriptableObject{}

As you can see it's going to be a StateMachine. Now I want kind of a window with a text field where I enter a name for a state and it creates a new class like:

public class Idle : State{}

And after that it creates the asset itself via:

AssetDatabase.CreateAsset<Idle>("/path/to/somewhere");

edit nearly working code

using System;
using System.IO;
using System.Linq;
using System.Text;
using AI.StateMachine.BaseClasses;
using UnityEditor;
using UnityEngine;

namespace AI.StateMachine.Editor
{
    public class ActionWizard : EditorWindow
    {
        [MenuItem("Tools/AI/StateMachine/ActionWizard")]
        static void Init()
        {
            // Get existing open window or if none, make a new one:
            ActionWizard window = (ActionWizard) EditorWindow.GetWindow(typeof(ActionWizard));
            window.Show();
        }

        private string actionName;

        void OnGUI()
        {
            actionName = GUILayout.TextField(actionName);
            if (GUILayout.Button("Create Action"))
            {
                //Get base class content
                string baseClassContent =
                    File.ReadAllText($"{Application.dataPath}/Scripts/AI/StateMachine/BaseClasses/SM_Action.cs");
            
                //refactor base class content to create derived class content
                string newClassContent = baseClassContent
                    .Replace("SM_Action", actionName)
                    .Replace("ScriptableObject", "SM_Action")
                    .Replace("abstract ", "")
                    .Replace("namespace AI.StateMachine.BaseClasses", "namespace AI.StateMachine.Assets.Actions.Scripts")
                    .Replace("//", "");
            
                //create derived class
                using (FileStream fs = File.Create($"{Application.dataPath}/Scripts/AI/StateMachine/Assets/Actions/Scripts/{actionName}.cs"))
                {
                    byte[] info = new UTF8Encoding(true).GetBytes(newClassContent);
                    fs.Write(info, 0, info.Length);
                }
                
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            
                //get type of created class
                var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).ToList();
                var inputType = allTypes.Find(type => typeof(SM_Action).IsAssignableFrom(type) && type.Name == actionName);
            
                //null....
                //if type was created before it works and finds the desired type
                Debug.Log(inputType);
            
                //create scriptable object instance of created type
                //  var so = ScriptableObject.CreateInstance(inputType);
          
                //save scriptable object asset
                // AssetDatabase.CreateAsset(so,"Assets/Scripts/AI/StateMachine/Actions/"+actionName + ".asset");
                // AssetDatabase.Refresh();
         
            }
        }
    }
}
Pascal
  • 15
  • 3
  • I think this question should be reopened or atleast it should point a newer question. The related question is asked 11 years ago and also the answers are the same. – Eldar Jul 10 '22 at 08:48
  • 1
    @Eldar which newer question had you in mind? – rene Jul 10 '22 at 10:14
  • 1
    This sounds like an XY problem. What are you actually trying to do and why do you think you should use try to solve it this way? Depending on what you are trying to do there might be other solutions like interfaces or base classes. – Progman Jul 10 '22 at 10:41
  • What i try to say, solutions like source generators wasn't available 11 years ago @rene – Eldar Jul 10 '22 at 13:06
  • @Eldar CompilerServices and Il.Emit existed almost from the start so not sure what you mean. Anyway, after the edit this turns out to be a different problem that needs a different solution so it is open now for that reason. – rene Jul 10 '22 at 13:25

1 Answers1

1

You can create type from string using:

Type.GetType(string typeAssemblyQualifiedName);

But you need to use Type.assemblyQualifiedName for that so "Idle" may not work if you use namespaces or assemblies, other option would be to get all types in current domains

var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes());

and find your desired type on that list somehow

var inputType = allTypes.Find(type => typeof(State).IsAssignableFrom(type) && type.Name == inputName);

then we create scriptable object instance using that type

var so = ScriptableObject.CreateInstance(inputType);
  • After trying it I have a Problem. Getting the type after creating the file returns null. When I create it before it works. So I guess I have to reload the assembly or something. AssetDatabase.Refresh(); doesn't work – Pascal Jul 10 '22 at 19:20
  • try AssetDatabase.SaveAssets(); and maybe EditorUtility.SetDirty() on created asset before saving – Paweł Łęgowski Jul 10 '22 at 20:45
  • AssetDatabase.SaveAssets(); didn't worked. EditorUtility.SetDirty() can also not work, GetAssemblies() does not find the newly created type, so i can not create an asset with type null. I pasted my code above – Pascal Jul 10 '22 at 20:58
  • So you should probably have asset postprocessor to carry on from here. https://docs.unity3d.com/ScriptReference/AssetPostprocessor.html – Paweł Łęgowski Jul 11 '22 at 09:35