-2

I'm generating a random number from 1-1000. I have 200 functions named function1, function4, function 10, function 11, etc. What I would like to do is execute a specific function depending on if the number generated requires a function, and ignore it if not. My first thought was to create an int[] containing all of the values that would trigger a function, and if the int[] contains the random number to use if statements to figure out what the number is. I'm concerned that it must be a really crude solution to an easy problem though. I know the "best way" to do something is subjective, but is there a better way to accomplish this?

NomadicBinary
  • 67
  • 1
  • 2
  • 8
  • 7
    You really have 200 different functions?! – DavidG Nov 19 '18 at 15:11
  • 1
    How do you define if for the number n, the function f has to be called or not? – Cid Nov 19 '18 at 15:11
  • 2
    Maybe a `Dictionary`? – Alessandro D'Andria Nov 19 '18 at 15:14
  • @AlessandroD'Andria I had too in mind the usage of a dictionary – Cid Nov 19 '18 at 15:14
  • 1
    The requirements are quote broad and optimal solution depends. Could you be more specific? You can use reflection to find method by name or something to route the call (dictionary, indexer, switch/case, etc.). – Sinatr Nov 19 '18 at 15:15
  • Try creating an array/list of functions, i.e. `Func[] funcs = new[] {x => x, x => x + 5, x => x*x};` and then `int result = funcs[random.Next(funcs.Length)](123);` – Dmitry Bychenko Nov 19 '18 at 15:15
  • 2
    What is the actual problem you're trying to solve? – Flater Nov 19 '18 at 15:19
  • I haven't actually made the 200 functions yet, and I supposed I could make it more like 8-10, I should have elaborated. I'll rephrase. So I have 8-10 functions that each do something different and take different arguments/variables. So if the random number is 1, I want it to call function C using x variables. If the number is 2-4, do nothing. If the number is 5, call function E using x variable. If the number is 6, call function C and D using x and y variable. And so on. – NomadicBinary Nov 19 '18 at 15:39
  • So my solution was going to be to create a function for each possible situation and find a way to call each function depending on what the number was. Again I know that's not the best way to do it, I was thinking of a dictionary object so I may do that instead. I eventually plan to do this on a much larger scale than "only" a few hundred, so again I need to make sure I'm using an efficient method to do so. – NomadicBinary Nov 19 '18 at 15:39
  • What I'm actually doing is creating hundreds (Or thousands) of custom animations that will all be slightly different from each other. So it's necessary for me to do it manually, I just don't want to slow down my program because of the massive amount of different possible situations that can occur in the program. – NomadicBinary Nov 19 '18 at 15:43

4 Answers4

3

UPDATE: As per comments, I should probably have started out by pointing out that doing this for 200 functions is probably a good sign that there is some serious issue in your design. This is probably an XY question where you are trying to solve a problem in some crazy way and asking about your intended solution instead of asking about the problem itself.

That said I'll leave the original answer because it's still good advice when mapping a reasonable amount of function calls that can/will change during the life cylce of your app or dynamically as the code runs.


I won't get into why you are doing this, but I'll try to at least point you in the right direction so this doesn't become a complete nightmare when you need to modify/expand behavior:

You can map numbers to function calls using delegates and a dictionary. Assuming your functions take no arguments and return void you'd do:

var functionsMap = new Dictionary<int, Action>();
//map functions
var r = getSomeRandomNumber();

if (functions.TryGetValue(r), out var a)
    a(); //invoke function

Mapping functions is simply adding keys and values:

functionsMap.Add(1, () => function1());
functionsMap.Add(3, () => function3());
//etc.

If your functions take arguments or return values, you'd use the adequate delegate: Action<T>, Func<T1, T2> etc.

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • 1
    I specifically didn't suggest doing this because there's almost certainly a better way to do what OP is trying to achieve. Having 200 functions is likely a very bad idea. – DavidG Nov 19 '18 at 15:20
  • 2
    @DavidG yes, I agree, but its still a good chance to al least show some good practices. The whole set up smells bad, thats why I started by saying I won't get into why he's even trying to do this. – InBetween Nov 19 '18 at 15:22
  • But you're not really helping by doing this. I'm not going to downvote, but I wouldn't have added this answer myself. – DavidG Nov 19 '18 at 15:23
  • @DavidG yeah, you are probably right, I'll delete it. – InBetween Nov 19 '18 at 15:24
  • Leave it here now it's been posted I suppose. – DavidG Nov 19 '18 at 15:25
  • I haven't actually made the 200 functions yet, and I supposed I could make it more like 8-10, I should have elaborated. I'll rephrase. So I have 8-10 functions that each do something different and take different arguments/variables. So if the random number is 1, I want it to call function C using x variables. If the number is 2-4, do nothing. If the number is 5, call function E using x variable. If the number is 6, call function C and D using x and y variable. And so on. – NomadicBinary Nov 19 '18 at 15:40
  • So my solution was going to be to create a function for each possible situation and find a way to call each function depending on what the number was. Again I know that's not the best way to do it, I was thinking of a dictionary object so I may do that instead. I eventually plan to do this on a much larger scale than "only" a few hundred, so again I need to make sure I'm using an efficient method to do so. – NomadicBinary Nov 19 '18 at 15:40
  • What I'm actually doing is creating hundreds (Or thousands) of custom animations that will all be slightly different from each other. So it's necessary for me to do it manually, I just don't want to slow down my program because of the massive amount of different possible situations that can occur in the program. – NomadicBinary Nov 19 '18 at 15:43
  • The functions do take arguments, however I only have 8-10 functions that take 1-2 arguments each. I was planning to create individual functions because I wanted the flexibility to adjust what each animation does on an individual basis. But in reality there's only 8-10 different functions, but I want to use them in various combinations using various arguments. – NomadicBinary Nov 19 '18 at 15:45
  • @InBetween, thank you your description is very helpful. I think that's the best way for me to do it by instead keeping the 8-10 functions I have and using the dictionary objects to map what each function does. – NomadicBinary Nov 19 '18 at 16:13
  • Almost all of the 200 numbers that trigger functions will only trigger a single function each with 1-2 arguments, so that should be a cleaner way to accomplish what I'm trying to do. – NomadicBinary Nov 19 '18 at 16:13
  • I'm pretty new to programming, if it's not too much to ask could you give an example of how to add keys to the dictionary that pass arguments to the function? I'm looking up the syntax for Action now and it's not clicking for me how to incorporate it. When I have a working example and can change the values it helps me figure out what I'm doing more than trying to guess what syntax I need to be using. – NomadicBinary Nov 19 '18 at 16:13
  • You've been so much help so either way I'll mark this answer correct, it would help me understand it a lot better if you could post a single line of how to add an item to the dictionary with one or two arguments pointing to a function. – NomadicBinary Nov 19 '18 at 16:13
  • @InBetween, I think I understand actually. So instead of functionsMap.Add(1, () => function1()); I would be doing functionsMap.Add(1, () => Action); Is that right? – NomadicBinary Nov 19 '18 at 16:17
  • Never mind I just replaced function1() with the functions including the variables needed. I figured it out, thanks for your help. – NomadicBinary Nov 19 '18 at 16:45
0

You can use reflection to invoke appropriate method:

Type exampleType = exampleObject.GetType();
MethodInfo exampleMethod = exampleType.GetMethod(methodName); 
exampleMethod.Invoke(this, null);

Where methodName can be created using your random number.

Kokonen
  • 31
  • 1
0

Without commenting on the wisdom of having 200 functions named the way yours are, you can use reflection to determine whether a given functionX() exists, like so:

public void ExecuteDynamicMethod(int number)
{
    // Modify these two lines with your app's dll/exe and class type:
    Assembly assembly = Assembly.LoadFile("...Assembly1.dll");
    Type type = assembly.GetType("YourClassType");

    if (type != null)
    {
        MethodInfo methodInfo = type.GetMethod("function" + number);

        if (methodInfo != null)
        {
            object classInstance = Activator.CreateInstance(type, null);
            methodInfo.Invoke(classInstance, null);  // null = "no function arguments"
        }
    }
}

This can then be called for a given value like

ExecuteDynamicMethod(14);

See this SO answer for the inspiration behind this.

NRitH
  • 13,441
  • 4
  • 41
  • 44
0

Reflection can be used for this purpose. I want to give and keep below example for not only the objective of the question but also for future reference. Also, of course that many function is not good but below code shows the approach that can work with many functions if they have similar name (like starting with "function" keyword).

Assume below is Methods.cs

using System;
using System.Reflection;

namespace YourMethodNamespace
{    
    public class YourMethodClass
    {
        public void function1()
        {
            Console.WriteLine("Function-1");
        }

        public void function2()
        {
            Console.WriteLine("Function-2");
        }

        ...

        public void function200()
        {
            Console.WriteLine("Function-200");
        }

        public static void invokeMethodsDynamically(int randomNumber){
            Type yourClassType = typeof(YourMethodClass);
            ConstructorInfo yourClassConstructorInfo = yourClassType.GetConstructor(Type.EmptyTypes);
            object yourClassObject = yourClassConstructorInfo.Invoke(new object[]{}); 

            //If the constructor has parameters, then we can pass them by this way. Like below;
            /*ConstructorInfo yourClassConstructorInfo = yourClassType.GetConstructor(new[]{typeof(int)});
            object yourClassObject = yourClassConstructorInfo.Invoke(new object[]{3});
            */

            MethodInfo[] methodInfoArr = yourClassType.GetMethods();
            foreach(MethodInfo methodInfo in methodInfoArr){
                if(methodInfo.Name == "function" + randomNumber){
                    methodInfo.Invoke(yourClassObject, null);
                }
            }
        }
    }
}

Let's say below is Program.cs

using System;
using YourMethodNamespace;

namespace YourProgramNamespace
{       
    public class YourProgramClass
    {
        public static void Main()
        {
            Random random = new Random();
            int randomNumber = random.Next(1, 201);             

            //If Methods.cs is in another Assembly

            /*string pathToDllAssembly = @"Domain.dll";
            Assembly dllAssembly = Assembly.LoadFrom(pathToDllAssembly);
            Type methodsClassType = dllAssembly.GetType("YourMethodNamespace.YourMethodClass");
            ConstructorInfo methodClassConstructorInfo = methodsClassType.GetConstructor(Type.EmptyTypes);
            object methodsClassObject = methodClassConstructorInfo.Invoke(new object[]{});
            MethodInfo methodInfo = methodsClassType.GetMethod("invokeMethodsDynamically");
            methodInfo.Invoke(methodsClassObject, new object[]{randomNumber});
            */

            YourMethodClass.invokeMethodsDynamically(randomNumber, null);
        }
    }
}

Also for testing and observing, below link can be used.

https://repl.it/@erdsavasci/ReflectionTest

Erdem Savasci
  • 697
  • 5
  • 12