Asperger
Asperger

Reputation: 3222

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...

Upvotes: 8

Views: 12917

Answers (6)

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37000

Delegates are exactly what you need:

var list = new List<Action>();

...

void fooBar() {
    ....
}

...

list.Add(fooBar);

The Action is actually nothing but a delegate, simply look its definiton and you´ll see it is similar to a delegate expecting nothing and returning nothing. If you want to pass parameters use any of it´s generic versions, for example Action<T>. If you also need to add methods that return something use the Func-delegate instead.

EDIT: Every delegate has its own type so you can´t mix them and put them alltogether into one single collection, except you use a collection of type Delegate:

var list = new List<Delegate>();

In this case you can´t use urual braces to call the actual delegate, instead you have to use DynamicInvoke and pass the arguments according to the delegates signature.

list[0].DynamicInvoke(args);

Upvotes: 12

Dai
Dai

Reputation: 155145

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.

Upvotes: 8

user734028
user734028

Reputation: 1111

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");

}

Upvotes: 2

Maksim Simkin
Maksim Simkin

Reputation: 9679

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");       
}

Upvotes: 3

Andrew Monks
Andrew Monks

Reputation: 666

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

Upvotes: 2

Codor
Codor

Reputation: 17605

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;

Upvotes: 3

Related Questions