Call random method directly instead of using a lot of if-statements, C#

Viewed 80

Relative newcomer to c# here. Let’s say I have 50 different methods a1(), a2(), … a50() and I want to call a random one. One way to do it is of course to generate a random int, nr, between 1 and 50 and then use a lot of if statements like if(nr == 1){ a1() } and so on. Quite cumbersome - can I do something smarter? Is it for example possible to do something along the lines of creating a string which is initially only “a” and then adding nr as a string and then calling that string as method? Like this:

Public void RandomMethod()
{
    nr = Random.Range(1,51);
    string = ‘a’ + nr.tostring();
    string();
}

I know this doesn’t work, but something like this instead of my first idea would save me hundreds of lines of code Any response is appreciated

4 Answers

One option would be to put your functions into a collection, say a List for example. Then you could randomly index into that collection to get a random function to call. You would generate a random index between 0 and the length of the List minus 1. This could apply generally to any number of functions then (50 or otherwise).

So, assuming we have fifty methods that all have a signature like

void SomeMethod()
{
    ...
}

You could declare an array like below, this is an array of Action delegates

var methods = new Action[]
{
    SomeMethod,
    SomeOtherMethod,
    () => _ = SomeFunctionWithAHardcodedParameter("Wibble"),
    ...
}

Then you could call a random method by doing,

method[Random.Next(methods.Length)]();

To do exactly what you asked (and, I have no clue why you'd want to), consider something like this:

Create a delegate that matches the call signature of all of your methods (they all have to have the same call signature or ... I really can't imagine what you'd want to do if they didn't). You could use an Action or Func declaration, but I'm going to make it clear here:

public delegate void SomeMethod(int i);

Then write your 50 methods. All their call signatures will match the delegate:

public static void Method1(int i) { System.Console.WriteLine($"{nameof(Method1)}: {i}"); }
public static void Method2(int i) { System.Console.WriteLine($"{nameof(Method2)}: {i}"); }
public static void Method3(int i) { System.Console.WriteLine($"{nameof(Method3)}: {i}"); }
public static void Method4(int i) { System.Console.WriteLine($"{nameof(Method4)}: {i}"); }
// ...
public static void Method50(int i) { System.Console.WriteLine($"{nameof(Method50)}: {i}"); }

Then create an array of delegates:

public static SomeMethod[] Methods = new SomeMethod[]
{
    Method1,
    Method2,
    Method3,
    Method4,
    //...
    Method50,
};

And then a method that picks 1 or more from the list at random and runs them:

public void Run5RandomMethods()
{
    Random random = new Random();
    for(int i = 0; i < 5; i++)
    {
        var randNumber = random.Next(50);
        var method = Methods[randNumber];
        method.Invoke(i);
    }
}

Note: this is untested, I'm not going to create 50 dummy methods for you. If you find an issue, comment below and I'll fix the code

By the way, what you show in your question (composing the name of the method by concatenating a string and the string representation of a number) is doable using a technology known as Reflection. Let me know if you really want to do that.

First off, I just want to say something similar to what others have already said: you should readdress whether you need 50 methods named a1(), a2(), ..., a50(), and rethink what the problem you're trying to solve is (which you haven't provided enough information for us to help you with).

If that was hyperbole, try to avoid doing that; it may muddy the responses to solve a perceived problem ("why do you have 50 poorly-named methods?") instead of your actual problem ("can I execute a randomly selected method?" <- still a weird question, but who am I to judge...).

That out of the way, you can use something like Reflection. This can be "dangerous" and expensive when executing, so use with caution... or better yet don't use it, but be aware of it, because it can lead you to think Reflection is the answer to problems you don't actually have.

Anyway, you can:

// have an instance of an object
var obj = new ClassName();

// get all the methods of the object
var methodInfos = typeof(ClassName).GetMethods();

// filter them somehow
var filteredMethodInfos = methodInfos.Where(m => Regex.IsMatch(m.Name, @"\a[\d]{1,2}")).ToArray();

// get a random one and invoke it
var rnd = new Random();
filteredMethodInfos[rnd.Next(filteredMethodInfos.Length)].Invoke(obj, null);

I haven't tested this, but it should in theory work.

But again: don't use reflection if you don't have to. There's probably an issue with your root question (as Tim Schmelter said, this is an "XY-problem") if your answer is "randomly execute 1 of 50 methods".

Related