'Store methods in an array and call them in C#

In javascript we can do this:

var arr = [];

function fooBar() {
    console.log('Hello World');
}

arr[0] = fooBar;

arr[0]();

Essentially each function is a real object and I can store them in an array if I want to. My question is, since C# doesnt have pointers, what is the best way to handle such as scenario? I mean how can I store function references into arrays?

I know we have something called delegates but im not sure if this is the right thing for the task...



Solution 1:[1]

Delegates are the right thing for the task - they're equivalent to a strongly-typed function pointer.

Because each delegate is its own type you cannot mix-and-match different delegate types in an array type to a single delegate-type, you can use the parent System.Delegate to allow you to store delegates of different types in the array, though you lose the ability to invoke them directly without some side-channel that informs your program of their arguments.

For example:

public static String Meow(Cat cat) { return "meow"; }
public static String Purr(Cat cat) { return "purr"; }

delegate String CatSound(Cat cat);

CatSound[] catSounds = new CatSound[] {
    Meow,
    Purr
};

You can then invoke them directly:

Cat orion = new Cat();
catSounds[0]( orion ); // meow
catSounds[1]( orion ); // purr

If you want to add a DogSound delegate to your collection, you'll have a harder job: you need to use Delegate[] instead...

delegate String DogSound(Dog dog);

Delegate[] petSounds = new Delegate[] {
    new CatSound( Meow ),
    new CatSound( Purr ),
    new DogSound( Woof ),
    new DogSound( Bark ),
}; // note that C# compiler allows shorthand syntax where simply `Meow` is behind-the-scenes converted into `new CatSound( Meow )`.

...and you have to invoke it using the DynamicInvoke method ( https://msdn.microsoft.com/en-us/library/system.delegate.dynamicinvoke(v=vs.110).aspx ) which means you'll lose compile-time verification of correct arguments, instead any call made with incorrect arguments will fail at runtime with a MemberAccessException.

Dog pupper = new Dog();
Cat orion = new Cat();

petSounds[0].DynamicInvoke( orion );
petSounds[1].DynamicInvoke( orion );
petSounds[2].DynamicInvoke( pupper ); // ok, this is a DogSound
petSounds[3].DynamicInvoke( orion ); // this will fail at runtime because you're passing a Cat into a DogSound delegate

You can also think of delgates as "an interface for a single method".

Prior to the .NET Framework 3.5, you generally needed to define your own delegate types using the delegate keyword (note that the delegate keyword is also overloaded for anonymous functions in C# 3.0), however there is now System.Action and System.Func which serve 95% of cases where you would have previously needed to define your own type. Indeed, today my delegate CatSound is unnecessary, you could just use Func<Cat,String> instead.

Solution 2:[2]

Given that the functions to call have the same signature, it could be done by using the predefined generics for delegates as follows.

Func<int,int> Square = x => x*x;
Func<int,int> Successor = x => x+1;
Func<int,int> Functions[] = new Func<int,int>[]{ Square, Successor };

int A = Functions[0](2); // A gets assigned 4;
int B = Functions[1](1); // B gets assigned 2;

Solution 3:[3]

You could Store Action or Func objects, someting like:

void Main()
{
    var arr = new object[2];
    arr[0] = 1;
    arr[1] = (Action)DoIt;

    foreach (var a in arr)
    {
        if (a is Action)
        {
            ((Action)a)();
        }
        else
        {
            Console.WriteLine(a.ToString());
        }
    }
}


public void DoIt()
{
    Console.WriteLine("did");       
}

Solution 4:[4]

Consider actions (depending on .net verion)

https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx

List<Action<string>> actions = new List<Action<string>>();

    actions.Add(() => {
      //do stuff
    });

or if you need rturn values use Func: https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx

Solution 5:[5]

yea through delegates you can:

static void iammain()
{
  List<Action> lst = new List<Action>();
  lst.AddRange(new Action[] { proc1, proc2, proc3 });
  for (int i = 0; i < lst.Count; i++)
  {
    lst[i]();

  }

}
static void proc1()
{
  Console.WriteLine("i am proc1");

}
static void proc2()
{
  Console.WriteLine("i am proc2");

}
static void proc3()
{
  Console.WriteLine("i am proc3");

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Codor
Solution 3 Maksim Simkin
Solution 4 Andrew Monks
Solution 5 user734028