Reputation: 3222
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
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
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
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
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
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
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