So, I am making a program designed to complete some automated process. I have a form that allows the user to build custom automation processes. The structure of this automation process is as follows:
public class AutomationScript
{
public string FilePath;
public List<AutomationEvent> Events;
public AutomationScript()
{
Events = new List<AutomationEvent>();
}
}
public class AutomationCommand
{
public AutomationCommandType Type;
public int Parameter;
public AutomationCommand(AutomationCommandType _type, int _parameter)
{
Type = _type;
Parameter = _parameter;
}
}
public struct AutomationEvent
{
public string Name;
public bool LoopEnabled;
public List<AutomationCommand> Commands;
}
public enum AutomationCommandType
{
WaitSecs,
CollectSample,
CollectBackGround,
StopCollection,
LoopStart,
LoopEnd,
}
Now, when the user initiates the process to run a thread is created and it iterates through the commands. The basic setup is as follows:
private void runAutomationScript()
{
while (automationON)
{
foreach (AutomationEvent aEvent in fullAutomationScript.Events)
{
int loopStartIndex = 0;
int loopEndIndex = 0;
foreach (AutomationCommand command in aEvent.Commands)
{
while (!CommandCompleted) { } //Will stay in loop until the hardware module is finished receiving spectra
switch (command.Type)
{
case AutomationCommandType.CollectBackGround:
RequestedBackgroundScans = command.Parameter;
spectralCollection.getBackGroundSpectra(RequestedBackgroundScans);
CommandCompleted = false;
break;
case AutomationCommandType.CollectSample:
RequestedSampleScans = command.Parameter;
spectralCollection.getSampleSpectra(RequestedSampleScans);
CommandCompleted = false;
break;
case AutomationCommandType.WaitSecs:
Thread.Sleep(command.Parameter * 1000);
break;
case AutomationCommandType.StopCollection:
automationON = false;
break;
case AutomationCommandType.LoopStart:
loopStartIndex = aEvent.Commands.IndexOf(command);
break;
case AutomationCommandType.LoopEnd:
loopEndIndex = aEvent.Commands.IndexOf(command);
//Wehn the loop end is reached it will get the index of the start and end and grab a sublist and iterate over that continuously.
int firstCommandIndex = loopStartIndex + 1;
List<AutomationCommand> loopedCommands = aEvent.Commands.GetRange(firstCommandIndex, loopEndIndex - firstCommandIndex );
break;
}
}
}
}
OnAutomationFinished(EventArgs.Empty);
}
Now, at this point it works fine. I am trying to allow the user to define a loop point for the process to loop through. As you can see there is an AutomationCommand called LoopStart and LoopEnd. I am trying to figure out how to loop through this second sub loop without copying code into another function. I am toying with the idea of making some recursive definition of this command loop. Any ideas will help.
Related
TL;DR ?:(
hi, I'm creating a source generator, It's been a pain since I started TBH.
I have a class:
public class CsharpTypeBase
{
public CsharpTypeBase(int childCount = 0)
{
childCount++;
if (childCount < 5)
{
Child = new(childCount);
}
}
public bool IsSimple { get; set; }
public bool IsArray { get; set; }
public bool IsIEnumerable { get; set; }
public ref CsharpTypeBase? Child
{
get => ref _child;
}
public string? ValueIfIsSimple
{
get => _valueIfIsSimple;
set
{
IsSimple = true;
_valueIfIsSimple = value;
}
}
public CsharpClassModel ClassModel
{
get => _classModel;
set
{
IsSimple = false;
_classModel = value;
}
}
private string? _valueIfIsSimple;
private CsharpClassModel _classModel = new();
private CsharpTypeBase? _child;
}
which is a base class for other CSharp types that I have(ex: ReturnTypes,Parameters,Properties)
with the following code im trying to parse c# classes into simpler versions(and after that do something with them):
public static CsharpTypeBase Convert(TypeSyntax typeSyntax)
{
var output = new CsharpTypeBase();
FromTypeSyntax(typeSyntax,ref output);
return output;
}
private static void FromTypeSyntax(TypeSyntax typeSyntax,ref CsharpTypeBase output)
{
switch (typeSyntax)
{
case PredefinedTypeSyntax predefinedTypeSyntax:
output.ValueIfIsSimple = predefinedTypeSyntax.Keyword.ValueText;
output.IsIEnumerable = false;
output.IsArray = false;
break;
case IdentifierNameSyntax identifierNameSyntax:
CsharpClassModel.RecursivelyWalkThroughTheClass(identifierNameSyntax.Identifier.ValueText,output);
break;
case ArrayTypeSyntax arrayTypeSyntax:
output.IsArray = true;
output.IsIEnumerable = false;
FromTypeSyntax(arrayTypeSyntax.ElementType,ref output.Child!);
break;
case GenericNameSyntax genericNameSyntax:
var (innerClass,isEnumerable) = FindTheMostInnerType(genericNameSyntax);
output.IsIEnumerable = isEnumerable;
FromTypeSyntax(innerClass,ref output.Child!);
break;
}
}
as you can see it's a recursive function, and its doing just fine, the only problem I have with this design is (that Child property) it's not really memory friendly and stable because of my base class, by default it's creating 5 child class(which is the same type as my base, it's stupid but I cant thing of anything else).
I want this to be more efficient, what if I only need 2 children? or worse, what if I needed more children to be created? I need the Exact Count otherwise it will OverFlow (by creating infinite objects) or blow up:
FromTypeSyntax(arrayTypeSyntax.ElementType,ref output.Child!);
this code should somehow set a maximum count for :
Child = new();
And the reason I need that Child property is to parse/convert this kind of incoming types:
List<string>[] one,
List<string[]> two,
Task<List<IReadOnlyCollection<FirstDto>>> three,
AnotherDto[] four,
string five,
int[] six,
List<List<List<List<List<List<string>>>>>> seven
Thank you for reading this question.
I solved My problem by making the Child object nullable:
public CsharpTypeBase? Child { get;set; }
and using it like this :
FromTypeSyntax(child, output.Child ??= new());
This is my object
public class Totals {
public int Total1 { get; set; }
public int Total2 { get; set; }
public int Total3 { get; set; }
public int Total4 { get; set; }
}
Incrementing the values of Total1 and Total2 using calculateTotals method
private Totals calculateTotals(Totals t) {
if (//condition) {
t.Total1 += 1;
} else {
t.Total2 += 1;
}
return t;
}
**Incrementing value of Total3 and Total4 of the same object with same conditions at a different location using different method calculateOtherTotals, at this point I only need to update Total3 and Total4 **
private Totals calculateOtherTotals(Totals t) {
if (//condition) {
t.Total3 += 1;
} else {
t.Total4 += 1;
}
return t;
}
I am new to c# , I need to increment the values Total1,Total2 and Total3,Total4 separately and the code which I have is working fine
Is there a way to improve my code?, how can I avoid creating two different methods which pretty much does the same logic on different properties? is there a way to create only 1 method to achieve my functionality?
You could do it this way, but essentially the amount of code doesn't change.
This adds a judgment:
Totals calculateTotals(Totals t, bool Flag)
{
//function1:
if (Flag)
{
if (true)
{ //(condition) {
t.Total1++;
}
else
{
t.Total2++;
}
}
//function2:
else
{
if (true)
{ //(condition) {
t.Total3++;
}
else
{
t.Total4++;
}
}
return t;
}
Call it like this:
Totals totals = new Totals();
totals.Total1=0;
totals.Total2=0;
totals.Total3=0;
totals.Total4=0;
calculateTotals(totals,true);//function1:
calculateTotals(totals,false);//function2:
Reflection is one way, though its slow and not a Domain Specific Language:
Type totalsType = typeof(Totals);
var totalToIncrement = condition;
PropertyInfo prop = totalsType.GetProperty("Total" + totalToIncrement);
prop.SetValue(null, 76);
Or perhaps you want to abstract the properties you're incrementing:
private Totals calculateTotals(Totals t)
{
bool condition = true;
AbstractAdds(ref t.Total1, ref t.Total2, condition);
return t;
}
private void AbstractAdds(ref int a, ref int b, bool condition = false)
{
if (condition)
{
a++;
}
else
{
b++;
}
}
}
public class Totals
{
public int Total1;//{ get; set; }
public int Total2;//{ get; set; }
public int Total3;//{ get; set; }
public int Total4;//{ get; set; }
}
I'd personally have a List<int> or int[3] and make the condition calculate the index 0-3:
var index = calcCondition;
Totals[index]++;
This way its extensible for more totals and you get inbuilt functions like LINQ, eg Totals.Sum().
Is there a way to improve my code?, how can I avoid creating two different methods which pretty much does the same logic on different properties? is there a way to create only 1 method to achieve my functionality?
Then it depends on how you want your method (function) to be. (E.g., how you define what your function will do and how your class and properties are characteristic—which, currently, many who want to help you still wonder about.)
Let me give another clear example.
Assume that you answer your additional requirement are:
My object has only 4 properties of "Total"
I want these new function to increment value only 1 when call, no need to add more than 1
This function is called from another class to modify my object value
I want my cool function name calculateOtherTotals being private, because of some unexplained reason such as “I don't like others knowing it exists”.
Then
public OtherClass{
Public Totals ExposeThePrivateCalculateOtherTotals(Totals t, bool IncrementT1 , bool IncrementT2 , bool IncrementT3, bool IncrementT4)
{
calculateOtherTotals(t, IncrementT1 , IncrementT2 , IncrementT3, IncrementT4);
}
Private Totals calculateOtherTotals(Totals t, bool IncrementT1 , bool IncrementT2 , bool IncrementT3, bool IncrementT4) {
if( IncrementT1 ) t.Total1 += 1; //choose your style
if( IncrementT2==true ) ++t.Total2;//choose your style
if( IncrementT3!=false ) t.Total3++; //choose your style
t.Total4 += IncrementT4==true?1:0;//choose your style
return t;
}
}
//In main (how to use)
Totals t= new Totals();
OtherClass doMyFunc = new OtherClass();
t = doMyFunc.ExposeThePrivateCalculateOtherTotals(t, true, false,false,false); // result of operation => t.total1 += 1;
t = doMyFunc.ExposeThePrivateCalculateOtherTotals(t, false, true,false,false); // result of operation => t.total2 += 1;
I am trying to make a todo application in c#. What I want to do is to be able to mark a Task as done somehow. Does anyone know how to do this?
This is my program class where i print out the list in a foreach:
using System;
namespace ToDo
{
class Program
{
static void Main(string[] args)
{
bool isRunning = true;
var collection = new TodoCollection();
while (isRunning)
{
var menu = new menu();
menu.Title();
menu.Options();
int choices;
choices = Convert.ToInt32(Console.ReadLine());
switch (choices)
{
case 1:
var inputNewTask = Console.ReadLine();
var task = new Task(inputNewTask, false);
collection.Add(task);
Console.Clear();
Console.ReadLine();
break;
case 2:
int counter = 0;
if (collection != null)
{
Console.WriteLine("Dagens uppgifter listas här nedanför");
foreach (Task newTask in collection)
{
counter++;
Console.WriteLine($"({counter}) [] {newTask.ShowTask()}");
}
int userInput = Convert.ToInt32(Console.ReadLine());
Task selectedTask = collection.GetTask(userInput);
selectedTask.Done();
}
break;
}
}
}
}
}
In my foreach loop there's a empty scuare brackets i wanna change to an "X" with user input.
Here is my class for my Todo collection containing my list:
using System.Collections;
using System.Collections.Generic;
namespace ToDo
{
public class TodoCollection : IEnumerable<Task>
{
//Deklarerar mina fält
List<Task> _CurrentTasks = new List<Task>();
//Funktion som låter användaren läga till nya tasks i listan
public void Add(Task NewTask)
{
_CurrentTasks.Add(NewTask);
}
public Task GetTask(int userInput)
{
return _CurrentTasks[userInput];
}
//Låter mig iterera igenomm listan _CurrentTasks
public IEnumerator<Task> GetEnumerator()
{
return ((IEnumerable<Task>)_CurrentTasks).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_CurrentTasks).GetEnumerator();
}
}
}
``´
And I also have a class for my Tasks here:
namespace ToDo
{
public class Task
{
string _Name;
bool isDone = false;
public Task(string name, bool done)
{
this._Name = name;
this.isDone = done;
}
public string ShowTask()
{
return this._Name;
}
public bool Done()
{
isDone = true;
return isDone;
}
}
}
I assume that option 2 is "mark task as done", and you print out the list of tasks, then ask the user which one to mark as done:
Console.WriteLine("Dagens uppgifter listas här nedanför");
foreach (Task newTask in collection)
{
counter++;
Console.WriteLine($"({counter}) [] {newTask.ShowTask()}");
}
int userInput = Convert.ToInt32(Console.ReadLine());
Task selectedTask = collection.GetTask(userInput);
selectedTask.Done();
Because "print the list of tasks" sounds like somethign we would want to do often, we should make it a method:
static void PrintListOfTasks(ToDoCollection what){
foreach (Task newTask in what)
{
counter++;
Console.WriteLine($"({counter}) [] {newTask.ShowTask()}");
}
}
Let's also make it show an X if the task is done and a space if it isn't:
Console.WriteLine($"({counter}) [{newTask.IsDone() ? 'X' : ' '}] {newTask.ShowTask()}");
But now there's another problem: Task doesn't have a way to tell if it's done or not, it only has a Done() method that marks it as done. You haven't used c# properties anywhere so I haven't used one in my recommendation here; instead we could make a method that just reports back the current Task state. CopyPaste the Done() method and change the pair so the existing single "mark it as done and report back the current state" (which is a little bit nonsensical, because we know what the state of a boolean must be if we just marked it as true) is instead two different methods, one that sets the value, and one that gets the value:
public void MarkAsDone()
{
isDone = true;
}
public bool IsDone()
{
return isDone;
}
Now you can use the get verison in your WriteLine display, and you can use your set version in the "mark task as done" menu option
Finally, you can adjust your loop that does option 2, so it's a logic of:
PrintList (pass in the collection)
Ask user which to mark as done
Mark it as done
Print List again to confirm to the user it was done
I doing a small project to map a network (routers only) using SNMP. In order to speed things up, I´m trying to have a pool of threads responsible for doing the jobs I need, apart from the first job which is done by the main thread.
At this time I have two jobs, one takes a parameter the other doesn´t:
UpdateDeviceInfo(NetworkDevice nd)
UpdateLinks() *not defined yet
What I´m trying to achieve is to have those working threads waiting for a job to
appear on a Queue<Action> and wait while it is empty. The main thread will add the first job and then wait for all workers, which might add more jobs, to finish before starting adding the second job and wake up the sleeping threads.
My problem/questions are:
How to define the Queue<Actions> so that I can insert the methods and the parameters if any. If not possible I could make all functions accept the same parameter.
How to launch the working threads indefinitely. I not sure where should I create the for(;;).
This is my code so far:
public enum DatabaseState
{
Empty = 0,
Learning = 1,
Updating = 2,
Stable = 3,
Exiting = 4
};
public class NetworkDB
{
public Dictionary<string, NetworkDevice> database;
private Queue<Action<NetworkDevice>> jobs;
private string _community;
private string _ipaddress;
private Object _statelock = new Object();
private DatabaseState _state = DatabaseState.Empty;
private readonly int workers = 4;
private Object _threadswaitinglock = new Object();
private int _threadswaiting = 0;
public Dictionary<string, NetworkDevice> Database { get => database; set => database = value; }
public NetworkDB(string community, string ipaddress)
{
_community = community;
_ipaddress = ipaddress;
database = new Dictionary<string, NetworkDevice>();
jobs = new Queue<Action<NetworkDevice>>();
}
public void Start()
{
NetworkDevice nd = SNMP.GetDeviceInfo(new IpAddress(_ipaddress), _community);
if (nd.Status > NetworkDeviceStatus.Unknown)
{
database.Add(nd.Id, nd);
_state = DatabaseState.Learning;
nd.Update(this); // The first job is done by the main thread
for (int i = 0; i < workers; i++)
{
Thread t = new Thread(JobRemove);
t.Start();
}
lock (_statelock)
{
if (_state == DatabaseState.Learning)
{
Monitor.Wait(_statelock);
}
}
lock (_statelock)
{
if (_state == DatabaseState.Updating)
{
Monitor.Wait(_statelock);
}
}
foreach (KeyValuePair<string, NetworkDevice> n in database)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(n.Value.Name + ".txt")
{
file.WriteLine(n);
}
}
}
}
public void JobInsert(Action<NetworkDevice> func, NetworkDevice nd)
{
lock (jobs)
{
jobs.Enqueue(item);
if (jobs.Count == 1)
{
// wake up any blocked dequeue
Monitor.Pulse(jobs);
}
}
}
public void JobRemove()
{
Action<NetworkDevice> item;
lock (jobs)
{
while (jobs.Count == 0)
{
lock (_threadswaitinglock)
{
_threadswaiting += 1;
if (_threadswaiting == workers)
Monitor.Pulse(_statelock);
}
Monitor.Wait(jobs);
}
lock (_threadswaitinglock)
{
_threadswaiting -= 1;
}
item = jobs.Dequeue();
item.Invoke();
}
}
public bool NetworkDeviceExists(NetworkDevice nd)
{
try
{
Monitor.Enter(database);
if (database.ContainsKey(nd.Id))
{
return true;
}
else
{
database.Add(nd.Id, nd);
Action<NetworkDevice> action = new Action<NetworkDevice>(UpdateDeviceInfo);
jobs.Enqueue(action);
return false;
}
}
finally
{
Monitor.Exit(database);
}
}
//Job1 - Learning -> Update device info
public void UpdateDeviceInfo(NetworkDevice nd)
{
nd.Update(this);
try
{
Monitor.Enter(database);
nd.Status = NetworkDeviceStatus.Self;
}
finally
{
Monitor.Exit(database);
}
}
//Job2 - Updating -> After Learning, create links between neighbours
private void UpdateLinks()
{
}
}
Your best bet seems like using a BlockingCollection instead of the Queue class. They behave effectively the same in terms of FIFO, but a BlockingCollection will let each of your threads block until an item can be taken by calling GetConsumingEnumerable or Take. Here is a complete example.
http://mikehadlow.blogspot.com/2012/11/using-blockingcollection-to-communicate.html?m=1
As for including the parameters, it seems like you could use closure to enclose the NetworkDevice itself and then just enqueue Action instead of Action<>
I have a multilined textbox where I can write missons for a drone.
Example:
10 levantar
10 goto 50,40
10 goto 20,20
10 mayday
10 aterrar
I want to create a list that does this missoes step by step. Something like: takeoff, after takeoff goto that position and when reaches that positon goto the next, etc..
My question is: Is there a way to group this text on a list and when it finishes that task i simply remove the first position of the list and does the next?
private void executa_missao()
{
string[] linhas_separadas = null;
string[] pontos_separados = null;
for (int i = 0; i < tb_missoes.Lines.Length; i++)
{
linhas_separadas = tb_missoes.Lines[i].Split(null);
for(int k=0;k<drone.Length;k++)
{
listas_posicoes[k] = new List<PointF>();
if (linhas_separadas[0] == drone[k].ip_drone_final)
{
if (linhas_separadas[1] == "goto")
{
pontos_separados = linhas_separadas[2].Split(',');
drone[k].posicao_desejada = new PointF(Convert.ToSingle(pontos_separados[0]), Convert.ToSingle(pontos_separados[1]));
//guarda na lista as posicoes pretendidas
listas_posicoes[k].Add(new PointF(Convert.ToSingle(pontos_separados[0]), Convert.ToSingle(pontos_separados[1])));
}
else if (linhas_separadas[1] == "levantar")
{
drone[k]._droneClient.FlatTrim();
drone[k]._droneClient.Takeoff();
drone[k].subir_ate_altura = true;
}
else if (linhas_separadas[1] == "aterrar")
{
drone[k]._droneClient.Land();
}
}
}
Atm it's trying to do every step at the same time. I want to make step-by-step.
Use a Queue<T> instead of a List<T>
Then you can use the .Dequeue() function to get your current command, and remove it from the queue.
Creating sample working code for this behaviour can get very complicated and would take me a while, but the basic pattern would look as such:
public abstract class Command
{
public abstract bool IsComplete { get; }
public abstract void Execute();
}
public static class CommandExecutor
{
public static Queue<Command> commands;
public static Command current;
public static void Update()
{
if (commands.Count > 0
&& (current == null || current.IsComplete))
{
current = commands.Dequeue();
current.Execute();
}
}
}
Where the Update() method is called in recurring intervals.