-1

Is it possible to run a method in a script where the method's name is found from a text variable?

For example:


public text MyVariable;

public void Start()
{
    MyVariable = RunMeBaby;
    MyVariable();
} 

public void RunMeBaby()
{
    Debug.Log("You did it!");
}

In the above example I'm assigning the variable 'MyVariable' to 'RunMeBaby' (the name of the method I want to call) and then attempting to call it.

The above doesn't work for me, but is there another way?


EDIT TO ADD ADDITIONAL CLARIFICATION BELOW

I am currently creating my own card game. I've created a scriptable object (CardAsset) to handle some fields that all my populated cards will need. Stuff like:

Card Name (string)

Cost (int)

Image (image)

Description Text (string)

I'm now at the point all the other stuff for my prototype is complete (playing field, deck, etc), and I need to start actually making the effects for my cards. Since every card is different but some of the effects are the same (draw more cards and deal damage to a character are very common for instance), I figured I could alter my scriptable object CardAsset to include some scripts and variables:

Card Name (string)

Cost (int)

Image (image)

Description Text (string)

Effect1 (script)

Effect1Amount (int)

Effect2 (script)

Effect2Amount (int)

Effect3 (script)

Effect3Amount (int)

This way, I could create CardAssets with upto 3 effects on them (again such as dealing damage to a character or drawing cards) and then use something in my game to call those scripts with the associated variables when the player plays that card.

My issue is that I cannot attach scripts to my CardAsset, so I figured a suitable workaround would be for me to type in the name of a method (DealDamage, DrawCards) in the Effect1/Effect2/Effect3 slot on the CardAsset (changing them to a string), and then have something read them and call the associated method elsewhere.

I understand that this solution is prone to errors and could be painful to maintain/change, so is there a better way I could do it?

  • `Action a = RunMeBaby; a();` – Aluan Haddad Sep 18 '20 at 05:01
  • 2
    Please describe your use case .. I can't think of many where this would make a lot of sense ... Of course you can use reflection as mentioned in most answers .. the question is: Is this really what you want to do? Going by strings is not only very slow but also quite error prone and can (and will be) a pain in the a** regarding maintainability ... – derHugo Sep 18 '20 at 06:26
  • @derHugo I've described my use case here: https://stackoverflow.com/questions/63974091/looking-for-a-better-solution-than-using-strings-within-scriptable-objects-to-ca – QuietPenguin Sep 20 '20 at 02:11

3 Answers3

1

Hello and welcome to Stack Overflow,

I don't know the details about your text class, but from your question I assume it's a string container (so to say). You can do exactly what you are asking (calling a method based on a string) using reflection:

// You need the class name, so I just called it MyClass
public class MyClass 
{
    public void Start()
    {
        string methodName = "RunMeBaby";

        // Invoke the method using reflection
        typeof(MyClass).GetMethod(methodName)?.Invoke(this, null);
    } 
...

However this is a VERY expensive (and error prone) call. My suggestion would be to use a less versatile approach:

public void Start()
{
    // assuming text.Text is your string property
    string methodName = "RunMeBaby";
    
    CallMethod(methodName);
} 

private void CallMethod(string methodName)
{
    switch(methodName)
    {
        case nameof(RunMeBaby):
            RunMeBaby();
            break;
        case nameof(SomeOtherMethod):
            SomeOtherMethod();
            break;           
    }
}

private void RunMeBaby()
{

}

private void SomeOtherMethod()
{

}

NOTE: I don't know where you get your method strings from, but if it is not from some outer source (e.g. user input), you are best advised to use the nameof keyword instead of hard coded strings. If possible you should get rid of the strings altogether and replace them with an enum representing the callable methods for example, but this solution depends on your usecase.

Thomas
  • 1,225
  • 7
  • 16
0

If you want to call methods by name. you can use reflection:

Test type = new Test();
 typeof(Test).GetMethod("Hello").Invoke(type, new[] { "world" }); 
AdiletB
  • 77
  • 3
0

You can do so through reflection in C#. But before we get there, I would recommend if possible you make use of Action Delegate (https://learn.microsoft.com/en-us/dotnet/api/system.action?view=netframework-4.7.2) to which you can assign your method and later call it wherever you want. So, your code will look like:

public Action MyVariable =RunMeBaby;
MyVariable();

Now the reflection way:

public string MyVariable = "RunMeBaby";

public void Start()
{
    this.GetType().GetMethod(MyVariable).Invoke(this, null);
}

Above code assumes that method to be called ("RunMeBaby" in your case) is public.

https://learn.microsoft.com/en-us/dotnet/api/system.type.getmethod?view=netframework-4.7.1 https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/reflection

gkulshrestha
  • 855
  • 1
  • 6
  • 11