2

Now the simplest example i can give of what im talking about is as followed.

In Unity3D there are several methods. void Awake(), void Start().

So what I'm trying to create is several classes that all contain the method void Start() and I want the void Main() method to call all of these start methods dynamically. I do not want to have to type Class test = new Class() etc.

If anyone can head me in the correct direction or even give me some example code that would be great.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • 1
    You want that the main method will find all types that have a public `Start` method, create an instance of that type(if it has a default constructor) and then call that `Start` method? No matter if the type of a `Start` method was `FormatC`? What's the reason for such an aproach, whats the benefit? Let those types implement the same interface `IStartable`. – Tim Schmelter Aug 23 '17 at 12:57
  • 2
    `Awake(), void Start(), void Update()` come from base class `MonoBehaviour`. Engine probably keeps a list of all `MonoBehaviour` classes and runs `Start`, `Update`, etc. in a loop. – FCin Aug 23 '17 at 12:59
  • So pretty much every time i create a new class in my program i want it to log something to the console. So any class that i have void Start() inside i can then do something like Console.Write() so that i may print some text to the console – ShadowDragon Aug 23 '17 at 13:00
  • 1
    Well you must first derive from `MonoBehaviour`. Quote from documentation: "When you use C#, you must explicitly derive from MonoBehaviour." – FCin Aug 23 '17 at 13:01
  • Yes. But this has nothing to do with Unity3D im asking how it can be done. Im trying to implement something like that with in my own Console App. – ShadowDragon Aug 23 '17 at 13:02
  • 2
    Exactly the same way... change names. I think you need to understand how `Inheritance` works – FCin Aug 23 '17 at 13:03
  • Thank you all for your help. I have figured out how to do this now :) – ShadowDragon Aug 23 '17 at 14:28

3 Answers3

4

So you could loop through every type and figure out if that type has a method called Start with the exact signature you need. Perhaps better would be to create an interface and make all your classes implement that. For example:

public interface IStartable
{
    void Start();
}

public class SomeClass : IStartable
{
    public void Start()
    {
        Console.WriteLine("Starting inside SomeClass");
    }
}

Now you can loop through all loaded assemblies and search for implementations of IStartable, for example:

var instances = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(a => a.GetTypes())
    .Where(t => t.IsClass && typeof(IStartable).IsAssignableFrom(t))
    .Select(t => (IStartable)Activator.CreateInstance(t));

foreach (var instance in instances)
{
    instance.Start();
}

This is assuming all those classes have a public, parameterless constructor.

This will work but isn't particularly efficient. If you wanted to scale this up a bit, then you might want to look at other options such as Managed Extensibility Framework.

To make this more generic and useful in more situations, here it is wrapped in a method you can apply to any type:

public void RunOnAll<T>(Action<T> action) 
{
    var instances = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(a => a.GetTypes())
        .Where(t => t.IsClass && typeof(T).IsAssignableFrom(t))
        .Select(t => (T)Activator.CreateInstance(t));

    foreach (var instance in instances)
    {
        action(instance);
    }
}

So now you would call it like this:

RunOnAll<IStartable>(x => x.Start());
DavidG
  • 113,891
  • 12
  • 217
  • 223
0

I will not provide you code, but the mean idea is to do something like this:

  1. Create a abstract class or interface which all your wanted classes extends from
  2. Scan the Assembly for classes that inherit from that class https://stackoverflow.com/a/17680332/1514875
  3. You now have a list of classes
  4. Loop over the classes and use Activator.CreateInstance to create a instance https://msdn.microsoft.com/en-us/library/wccyzw83(v=vs.110).aspx
  5. Use reflection to get the method https://msdn.microsoft.com/en-us/library/system.type.getmethod(v=vs.110).aspx
  6. Call Invoke with your created instance on the returned MethodInfo https://www.dotnetperls.com/methodinfo-invoke
TryingToImprove
  • 7,047
  • 4
  • 30
  • 39
  • I believe this is what im looking for. Thank you very much! – ShadowDragon Aug 23 '17 at 13:15
  • 2
    Well steps 5 and 6 are not needed because you have an interface you know you can cast to (see my answer) – DavidG Aug 23 '17 at 13:16
  • Not sure if im doing something wrong. Im getting this error on runtime "System.InvalidCastException: Unable to cast object of type System.RuntimeType to type ClassTesting.ShadowX" – ShadowDragon Aug 23 '17 at 13:45
  • @DavidG Fair point, but not if he want "dynamic" methods.. :) – TryingToImprove Aug 24 '17 at 07:40
  • @ShadowDragon It a little hard to tell why you are getting the error. You might want to create a new question instead. – TryingToImprove Aug 24 '17 at 07:40
  • 1
    @TryingToImprove Well yes if you want to run a method using a string for example. However, if you just want to make this more generic, I would pass in a `Func`. I've added that to my answer. – DavidG Aug 24 '17 at 08:49
-4

Its not entirely clear what youre asking, but if you want to load and create class intances at run time, the area youre looking for is called reflection: (https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/reflection). This allows .net to effectively analyze and obtain information about its own codebase.

In your case, you would be able to load up all the of the classes you were interested in (based on their name, or some other rule), create instances and call the start method all without this information being available at compile time.

richzilla
  • 40,440
  • 14
  • 56
  • 86
  • It sounds more like OP needed to learn about inheritence and casting as the super class to be able to call the similar method in each of the instances, each of which can be created at run-time. You described something that answers a questions that is similar to what OP posted, but isn't quite what they actually asked. Reflection is good for accessing private methods and variable inside of a class, but not what OP really needed. – TheCrzyMan Aug 23 '17 at 13:07
  • So your answer probably got downvoted because it doesn't actually answer the question other than pointing OP in the direction of reflection. The last paragraph is really just the question stated again in different terms. – DavidG Aug 24 '17 at 09:21