How to call functions from data structure? - c#

I would like to be able to describe some actions as function calls represented in a datastructure. Then I would like to be able to loop through the data structure and call the functions.
This pseudo-code describes what I would like to achieve:
static void Main(string[] args)
{
Action[] actions = new Action[]
{
new Action(DoAction1(5)),
new Action(DoAction1(7)),
new Action(DoAction2("100201")),
};
foreach (Action action in actions)
{
action.<Run the action function>;
}
}
public static void DoAction1(int x)
{
}
public static void DoAction2(string x)
{
}
It kind of looks like delegates, but not quite.
Any ideas on how to achieve this?

This is what you're looking for?
Action[] actions = new Action[]
{
new Action(()=>DoAction1(5)),
new Action(()=>DoAction1(7)),
new Action(()=>DoAction2("100201"))
};
foreach (Action action in actions)
{
action();
}

The Action class in .net allows you to directly assign lambdas
var actions = new List<Action>
{
() => DoAction1(5),
() => DoAction1(7),
() => DoAction2("100201"),
};
then executing an array of actions can be done like :-
actions.ForEach(a => a());
then you can add more actions to the list
actions.Add(() => DoAction2("blah blah"));

may be you can use reflection
var methodNames = typeof(MyType).GetMethods(BindingFlags.Public |
BindingFlags.Static)
.Select(x => x.Name)
.Distinct()
.OrderBy(x => x);
OR
foreach (var property in yourObject.GetType().GetProperties())
{
if (property.PropertyType.GetInterfaces().Contains(typeof(IEnumerable)))
{
foreach (var item in (IEnumerable)property.GetValue(yourObject, null))
{
//do stuff
}
}
}

Since you seem not to want to use the Action class, you can check out the SharpByte codebase, specifically the SharpByte.Dynamic namespace. It allows evaluating statements and executing scripts with just a single method call, like this:
someContextObject.Execute("[executable code here]");
However, you can use it another way which may be what you're looking for. When you execute one of those dynamic compilation/execution extension methods, here's what's actually happening (paraphrased):
IExecutable executable = ExecutableFactory.Default.GetExecutable(ExecutableType.Script, "[source code here]", optionalListOfParameterNames, optionalListOfNamespaces);
If you wanted to evaluate an expression/function instead of run multiple-lined statements, you'd use ExecutableType.Expression . The main point is that you can keep a reference around to an IExecutable object and run it as many times as you like, passing different parameter values each time. You can also copy IExecutable objects freely using the .Copy() method of each; they are designed to be thread-safe but lightweight, and references or copies could thus be placed in a data structure for further (re)use. This post explains a bit more.

Related

Dynamically call a function in Windows Form

I'm building an app to test some equipment and the app will have 43 test steps (Step01.cs to Step43.cs). (tests are massive and need to be split in separate files)
In each .cs file there is a public static void Test(){} function.
At any given point the user can go back and redo a test and at the end of each test the user is asked if he wants to redo the next step(only if it has been previously done). If next step has never been done, it continues with the test as usual.
if (currentStep < maxStep )
{
for(int i = currentStep; i < maxStep; i++)
{
_form1.testNumberComboBox.SelectedIndex = i - 1;
if (MessageBox.Show($"{_form1.testNameComboBox.SelectedItem.ToString()} has already been tested.\nWould you like to retest?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
Step02.Test(_form1, sensor);
return;
}
}
_form1.testNumberComboBox.SelectedIndex = maxStep - 1;
}
My question is if it possible to do something like this Step{i}.Test(_form1, sensor); to call what test I need, as I don't really want to do if(i == 2){Step02.Test(_form1, sensor);}...if(i == 40){Step40.Test(_form1, sensor);} if the answer from the user is Yes.
I've done something like this in PHP a while back. Had variables $acc1, $acc2 ... $accX and was able to call them in a for(i) loop with ${"acc$i"}.
I'm not sure if it is possible in C# and that is why I'm asking. (I'm new to C#)
You can use Reflection or use a Dictionary<string, Action>.
Assuming you have test classes like this:
namespace MyTests
{
public class Test1
{
public static void Test() { }
}
}
Call the test using Reflection:
Find the class and the method using reflection and call it:
Assembly.GetExecutingAssembly().GetType("MyTests.Test1")
.GetMethod("Test").Invoke(null, null);
Call the test using Dictionary<string, Action>:
Initialize a Dictionary<string, Action>() like this once:
Dictionary<string, Action> tests = new Dictionary<string, Action>();
tests.Add("Test1", () => Test1.Test());
tests.Add("Test2", () => Test2.Test());
Then call by name whenever you need:
tests["Test1"]();
Combine both reflection and Dictionary<string, Action>:
Or you can combine both for better performance and easier init. Find all test in startup using reflection once:
Dictionary<string, Action> tests = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.FullName.StartsWith("MyTests.Test"))
.Select(t => t.GetMethod("Test"))
.ToDictionary(m => m.DeclaringType.Name,
m => new Action(() => m.Invoke(null, null)));
Run whenever you need:
tests["Test1"]();
tests["Test2"]();

How to run variable number of methods depending on user input in Windows Forms

I am struggling with the concept described below:
User checks x of 5 checkboxes with type of measurements and then he clicks "RUN".
On the "RUN" OnClick() I create a Measure class object.
class Measure
{
string measure_type;
SendCommandToArduino(string nameOfMeasurement)
...
}
I need to run those selected methods IN SEQUENCE (they CANNOT run asynchronous, because they use Serial COM).
I hardcoded something like this:
void Method1()
{
measurement.SendCommandToArduino("tetnienie");
}
void Method2()
{
measurement.SendCommandToArduino("jasnosc");
}
tPomiar1 = new Thread(Method1);
tPomiar1.Start();
tPomiar1.Join();
pomiar.DrawGraphTetnien(tetnienie_Chart);
tPomiar2 = new Thread(Method2);
tPomiar2.Start();
tPomiar2.Join();
MessageBox.Show("Done all measurements!");
No surprise - it worked. But:
I still don't know how to relate number of checked checkboxes with number of methods to run in these threads. Maybe I should hardcode MethodX for all measurements and then run threads from some List list_of_threads?
Threads are overkill for this purpose ( I guess ), cause the longest measurement takes about 10 seconds... Is there any other way?
ThreadPool, Tasks, async/await ? I am totally new to multi-tasking/threading
I also tried something like this, but I didn't finish this solution, it was too hardcore:
List<Thread> list_of_threads= new List<Thread>();
List<Action> measureToDo = new List<Action>();
// link those additions with checkboxes
measureToDo.Add(Method1);
measureToDo.Add(Method2);
measureToDo.Add(Method3);
int i = 0;
foreach (Action action in measureToDo)
{
//substring this one to get method's name!
string methodName = action.Method.Name.ToString());
methodName = methodName.Substring(4,6) // limit of 9 methods here haha
}
foreach (var item in measureToDo )
{
RunThread(item.Method.Name.ToString());
}
void RunThread(Action a)
{
Thread t;
t = new Thread(new ThreadStart(a.Method.Name)).Start();
}
For a measure_type I created a '5-bit' string -> Containg "1" if the checkbox on this position was checked.
"01000" / "10011" etc.
Thank You in advance for all hints/tips! :)
Perhaps you are overcomplicating things, and a simple solution would be perfectly well.
You can use Control.Tag property and add the name (as string) of the measure to everyone of your checkboxes. Then, you can enumerate your check-boxes, see which is checked, and get a list of strings with the names of the measures you need to perform.
Then, you need a single method to execute your measures. It should enumerate the list, and have a switch to map a measure to a method:
void ExecuteMeasures(List<string> measures)
{
foreach (string measure in measures)
{
switch (measure)
{
case "Measure 1": MeasureMethodOne(); break;
// and so on...
}
}
}
Then you don't need to run each measure method in a separate thread, because you want them to be executed sequentially. You only need to run the ExecuteMeasureMethod in a separate thread. Having it run for seconds, a separate thread is fine. Still, to keep things neat, use a long running task:
var listOfMeasures = new List<string>();
//Populate your list from the selection of check boxes
Task t = Task.StartNew ( ()=> ExecuteMeasures(listOfMeasures), TaskCreationOptions.LongRunning);
await t;
Here is my solution:
1. Define a Action array to store your methods
2. Get the values of checked items(checkbox1's value is 0, etc.) as the array indices
3. Invoke the relevant method in the array.
Codes are something like :
public static void Main()
{
Action[] actions = new Action[5];
actions[0] = Method1;
actions[1] = Method2;
string checkedValue = "1";
actions[int.Parse(checkedValue) - 1].Invoke();
}
static void Method1()
{
Console.WriteLine(1);
}
static void Method2()
{ }
Or you can simplify the code as below:
public static void Main()
{
Action[] actions = new Action[5];
actions[0] = ()=> { Console.WriteLine(1); };
actions[1] = ()=> { Console.WriteLine(2); };
string checkedValue = "1";
actions[int.Parse(checkedValue) - 1].Invoke();
}

"yield return" from event handler

I have a class which takes a stream in the constructor. You can then set up callbacks for various events, and then call StartProcessing. The issue is that I want to use it from a function which should return an IEnumerable.
Example:
public class Parser
{
public Parser(System.IO.Stream s) { // saves stream and does some set up }
public delegate void OnParsedHandler(List<string> token);
public event OnParsedHandler OnParsedData;
public void StartProcessing()
{
// reads stream and makes callback when it has a whole record
}
}
public class Application
{
public IEnumerable<Thing> GetThings(System.IO.Stream s)
{
Parser p = new Parser(s);
p.OnParsedData += (List<string> str) =>
{
Thing t = new Thing(str[0]);
// here is where I would like to yield
// but I can't
yield return t;
};
p.StartProcessing();
}
}
Right now my solution, which isn't so great, is to put them all the Things into a List which is captured by the lambda, and then iterate over them after calling StartProcessing.
public class Application
{
public IEnumerable<Thing> GetThings(System.IO.Stream s)
{
Parser p = new Parser(s);
List<Thing> thingList = new List<Thing>();
p.OnParsedData += (List<string> str) =>
{
Thing t = new Thing(str[0]);
thingList .Add(t);
};
p.StartProcessing();
foreach(Thing t in thingList )
{
yield return t;
}
}
}
The issue here is that now I have to save all of the Thing objects into list.
The problem you have here is that you don't fundamentally have a "pull" mechanic here, you're trying to push data from the parser. If the parser is going to push data to you, rather than letting the caller pull the data, then GetThings should return an IObservable, rather than an IEnumerable, so the caller can consume the data when it's ready.
If it really is important to have a pull mechanic here then Parser shouldn't fire an event to indicate that it has new data, but rather the caller should be able to ask it for new data and have it get it; it should either return all of the parsed data, or itself return an IEnumerable.
Interesting question. I would like to build upon what #servy has said regarding push and pull. In your implementation above, you are effectively adapting a push mechanism to a pull interface.
Now, first things first. You have not specified whether the call to the StartProcessing() method is a blocking call or not. A couple of remarks regarding that:
If the method is blocking (synchronous), then there is really no point in adapting it to a pull model anyway. The caller will see all the data processed in a single blocking call.
In that regard, receiving the data indirectly via an event handler scatters into two seemingly unrelated constructs what should otherwise be a single, cohesive, explicit operation. For example:
void ProcessAll(Action<Thing> callback);
On the other hand, if the StartProcessing() method actually spawns a new thread (maybe better named BeginProcessing() and follow the Event-based Asynchronous Pattern or another async processing pattern), you could adapt it to a pull machanism by means of a synchronization construct using a wait handle: ManualResetEvent, mutex and the like. Pseudo-code:
public IEnumerable<Thing> GetThings(System.IO.Stream s)
{
var parser = new Parser(s);
var waitable = new AutoResetEvent(false);
Thing item = null;
parser.OnParsedData += (Thing thing) =>
{
item = thing;
waitable.Set();
};
IAsyncResult result = parser.BeginProcessing();
while (!result.IsCompleted)
{
waitable.WaitOne();
yield return item;
}
}
Disclaimer
The above code serves only as a means for presenting an idea. It is not thread-safe and the synchronization mechanics do not work properly. See the producer-consumer pattern for more information.

Conditional traversal of a tree structure, adding extra parameter to action

I have a tree structure that has a Traverse function, the traverse function takes an action that it will perform on each layer:
public void Traverse(Action<ILayer> action)
{
action(this);
foreach (var child in children)
child.Traverse(action);
}
However I find myself about to write code like this:
private List<ILayer> filteredList = new List<ILayer>();
private string condition;
void AddLayerIf(ILayer layer)
{
if (layer.Type == "condition")
filteredList.Add(layer);
}
void main()
{
filteredList.Clear();
condition = "Image";
rootLayer.Traverse(AddLayerIf);
List<ILayer> allImageLayers = filteredList;
}
And that feels totally wrong. Could I send the two variables as parameters instead of having them global? or is there an even better trick I am missing? I started to write the action as a lambda but not sure that is right either
I did some lambda which feels much better! Any advice on improving welcome :)
ILayer imageLayers= new ImageFolder("Images");
rootLayer.Traverse(
(ILayer x) =>
{
if (x.Type == "Image")
imageLayers.AddChild(x);
});

Different behaviors with a for loop and a foreach loop with closures

I can't explain an issue I've run across. Basically I get a different answer if I use lambda syntax in a foreach loop than if I use it in a for loop. In the code below I register a delegate in a "dispatcher" class. I then later wrap the delegate on the way out in another delegate and return a list of these wrapped delegates. I then execute them. The expected output of executing the wrapped function list is 1,2. However I don't see that when I combine a lambda and a foreach loop.
This is not the code that is causing the problem, but the simplest case I could make to reproduce it. I would prefer not to discuss use cases of this, I'm more curious as to why I get behavior I'm not expecting. If I use the foreach loop below with the lambda syntax it fails. If I use the new Action() syntax and a foreach it works, if I use the lambda syntax in a for loop it works. Can anyone explain what is going on here. This has me really stumped.
public class Holder
{
public Holder(int ID, Dispatcher disp)
{
this.ID = ID;
disp.Register(Something);
}
public int ID { get; set; }
private void Something(int test) { Console.WriteLine(ID.ToString()); }
}
public class Dispatcher
{
List<Action<int>> m_Holder = new List<Action<int>>();
public void Register(Action<int> func)
{
m_Holder.Add(func);
}
public List<Action<int>> ReturnWrappedList()
{
List<Action<int>> temp = new List<Action<int>>();
//for (int i = 0; i < m_Holder.Count; i++) //Works - gives 1, 2
//{
// var action = m_Holder[i];
// temp.Add(p => action(p));
//}
foreach (var action in m_Holder)
{
temp.Add(p => action(p)); //Fails - gives 2,2
//temp.Add(new Action<int>(action)); Works - gives 1,2
}
return temp;
}
}
class Program
{
static void Main(string[] args)
{
var disp = new Dispatcher();
var hold1 = new Holder(1, disp);
var hold2 = new Holder(2, disp);
disp.ReturnWrappedList().ForEach(p => p(1));
}
}
This is the infamous "closing over the loop variable" gotcha.
Closing over the loop variable considered harmful (and part two)
Have you tried:
foreach (var action in m_Holder)
{
var a = action;
temp.Add(p => a(p));
}
This is the classic issue of a captured closure with a scope that isn't what you expect. In the foreach, the action has outer scope, so the execution captures the last value of the loop. In the for case, you create the action in inner scope, so the closure is over the local value at each iteration.

Categories

Resources