0

I have this class:

public abstract class MyClass
{
    public abstract string abstract         id     { get; protected set; }
    public abstract Dictionary<string, int> values { get; protected set; }

    public MyClass() { this.Initialize(); }
    void Initialize() { /*...*/ } 
}

I made multiple override scripts of this class and I want to initialize them at Start.

When the constructor is called and initialize method is invoked, the script initialize with some data and then it adds itself to the manager script.

The problem is that I don't want to do this:

public class Manager : MonoBehaviour
{
    public void Start()
    {
        new OverrideOfMyClass_1();
        new OverrideOfMyClass_2();
        new OverrideOfMyClass_3();
        new OverrideOfMyClass_4();
        //..
    }
}

I store all these override scripts inside certain folder.

So Instead I fetched all .cs type files from the Directory using DirectoryInfo and.. I got stuck after this point as I don't know how to get the class type and instantiate it, so that the constructor would be called and initialize method invoked.

Is there a way to do this?

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
UnknownUser
  • 327
  • 2
  • 14
  • 1
    The question only makes sense if you want to parse C# script files at runtime, in which case you should explain *how* you parse those files? The old CodeDOM or Roslyn? Both will return the types after compilation. – Panagiotis Kanavos Sep 12 '19 at 11:09
  • At runtime you can use reflection to find types that inherit from another type. There are many duplicate questions [like this one](https://stackoverflow.com/questions/5411694/get-all-inherited-classes-of-an-abstract-class) – Panagiotis Kanavos Sep 12 '19 at 11:10
  • Hey, yeah I want to do this at runtime. Well at the start of the application, so only once, when the manager is instantiated and Start() method in Manager is called. I could use Reflection, but is there really no way to get all .cs files and parse them into a specified class? Or some similar way? I would prefer not to use reflection, if possible of course. – UnknownUser Sep 12 '19 at 11:54
  • Do *what* at runtime? You still haven't said whether you want to parse files or not. There are no .cs files in an executable. The program has no idea where the OverrideOfMyClass classes came from, they all appear the same. And if you *do* parse source files, which library do you use? – Panagiotis Kanavos Sep 12 '19 at 11:55
  • If you want to find the types at runtime you can use [Assembly.GetTypes](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.gettypes?view=netframework-4.8) and simply filter them by name eg `Assembly.GetExecutingAssembly().GetTypes().Where(t=>t.BaseType==typeof(MyClass))` – Panagiotis Kanavos Sep 12 '19 at 12:03
  • Within this "MyClass" class I have other methods that are being invoked within the Manager class, so I need to get all MyClass override scripts and store them in the Manager class.I don't use any parser as I don't any that would do the job. I'm simply looking for a way to get all the script files of type MyClass from certain Directory and call their constructor. I was only referring to a parser, cause I thought maybe it's possible to use some parser that would parse .cs file or a text of .cs file to a class of type. – UnknownUser Sep 12 '19 at 12:11

2 Answers2

0

You can build a new assembly based on your cs file and then get the class information/constructor by reflection. This is not trivial code so I won't post everything here but as a start you should look at:

string[] sources;
RuntimeCompiler.DynamicAssemblyInfo dynamicAssemblyInfo;
var trees = sources.Select(s => CSharpSyntaxTree.ParseText(s));
OptimizationLevel optimizationLevel = OptimizationLevel.Release;
var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: optimizationLevel);
var references = ... list of dlls you need to include to compile properly
var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), trees, references, compilationOptions);
using (var ms = new MemoryStream())
{
    EmitResult result = compilation.Emit(ms);
    if (!result.Success)
    {
        ... display debug
    }
    ms.Seek(0, SeekOrigin.Begin);
    var assembly = Assembly.Load(ms.ToArray());
    ... call reflection from here to look for your type in the assembly

}
Bruno Belmondo
  • 2,299
  • 8
  • 18
0

Judging from your ability to do:

        new OverrideOfMyClass_1();
        new OverrideOfMyClass_2();
        new OverrideOfMyClass_3();
        new OverrideOfMyClass_4();

I assume the classes are being compiled into the assembly, in which case it's relatively simple to use reflection to instantiate the classes (though I note you're not keen on it so no offense taken if you don't like this solution).

Here's a reflection based option (assuming usings etc) if you're interested anyway:

var absType = typeof(MyClass);
var subTypes = absType.Assembly.GetTypes()
    .Where(t => t != absType && absType.IsAssignableFrom(t));
foreach(var type in subTypes)
{
    var subObj = Activator.CreateInstance(type) as MyClass;

    // Now you have a subObj if you want to do things with a MyClass object
    Console.WriteLine(subObj.id);
}
Max
  • 216
  • 2
  • 3