C# code invoke parameters count dosen't match - c#

is there anyone check my code?
it shows the parameter count dose not match.
void WriteFaceLog(string userID, string faceId, string size, string valid, string template)
{
if (lstvFace.InvokeRequired)
{
Action<string, string, string, string, string> action = WriteFaceLog;
this.Invoke(action, faceId, size, valid, template);
}
else
{
ListViewItem item = new ListViewItem(userID);
item.SubItems.AddRange(new[] { faceId, size, valid, template });
lstvFace.Items.Add(item);
}
}

The typical auto-invoke pattern (designed to simplify running method from any thread) will looks like this in your case:
void WriteFaceLog(string userID, string faceId, string size, string valid, string template)
{
if (this.InvokeRequired) // you can use lstvFace instead of this, it doesn't matter as both are in same thread, you can also omit this
this.Invoke((MethodInvoker)delegate { WriteFaceLog(userID, faceId, size, valid, template); });
else
{
}
}
In given case you are unlikely to miss any parameter (just re-pass them).

Related

How to pass var as another method`s parameter?

I am making a windows application.
At first I declared var and it contains another class method.
var ExtList = ExtTarget.GetExtTargets();
And GetExtTargets() is like this
public static List<ExtTarget> GetExtTargets()
{
var dt = SqlHelper.ExecuteDataTable(QueryHelper.ConnectionString,
#"
SELECT [seq],[SourceKind],[ExtKind],[DBKind],[ConnectionString]
,[FilePath],[TableName],[FileKind],[RowSplitter],[ColumnSplitter]
,[Title],[GroupName],[SyncOrder],[RepeatKind],[RepeatMonth]
,[RepeatDay],[RepeatHour],[RepeatMin],[RepeatWeek],[RepeatWeekNum]
,[LastSyncExecDate]
FROM [ExtTarget]
order by GroupName,SyncOrder");
return dt.Rows.Cast<DataRow>().Select<DataRow, ExtTarget>(a => ExtTarget.RowToModel(a)).ToList();
}
Then, I used it to foreach and then I want to pass Ext to another method's parameter.
Code is like this.
public void ProcessExtSync(object obj)
{
while (IsProcessGoing)
{
Thread.Sleep(ThreadDelay);
if (!IsProcessGoing) return;
var ExtList = ExtTarget.GetExtTargets();
foreach (var Ext in ExtList) // I want to use this Ext as parameter
{
while (IsSourceSyncGoing)
{
Thread.Sleep(ThreadDelay);
}
IsExtSyncGoing = true;
bool ExtSyncForceToRun = ConfigSettingHelper.Instance.IsServiceConfig(Words.ExtSyncForceToRun);
bool ExtSyncForceToRunOnlyError = ConfigSettingHelper.Instance.IsServiceConfig(Words.ExtSyncForceToRunOnlyError);
bool ExtSyncNeedToRun = ConfigSettingHelper.Instance.GetNextExecutingTime(Ext) < DateTime.Now;
if (ExtSyncForceToRun || ExtSyncNeedToRun)
{
//I want to pass Ext as parameter to this method
ServiceProcess.Instance.SyncExt();
if (ExtSyncForceToRun)
{
ConfigSettingHelper.Instance.SetServiceConfig(Words.ExtSyncForceToRun, false);
}
if (ExtSyncForceToRunOnlyError)
{
ConfigSettingHelper.Instance.SetServiceConfig(Words.ExtSyncForceToRunOnlyError, false);
}
}
if (!IsProcessGoing) return;
}
IsExtSyncGoing = false;
}
}
How can I modify that code? Please help me.
var is just a shortcut way of implicitly typing a variable. It saves some typing, but sometimes makes code harder to read when the reader can't determine the type. The compiler can figure out the strong type, though (or you'll get a compiler error), and if you hover over it in Visual Studio, the compiler will tell you the actual type.
With that out of the way, all you need to do is make sure that the method you want to pass your variable to takes in the type that you want to pass it (remember the type is not var, but in your case it is an ExtTarget).
The method you're calling should have a signature similar to this (although it may return any type):
public void SyncExt(ExtTarget extTarget)
{
// Implementation code here
}
Then in your code above you can call:
ServiceProcess.Instance.SyncExt(Ext);

Making part of a split string public, and the other part local

Apologies about the (possibly) basic question, but I am attempting to split a string, and making one part of the string public, so I can call it later in the form in a different class.
It is a simple Skype chat bot, and it reads the message sent to me for processing. However, I am attempting to make it so that if someone sent a command with two words - e.g. !command name - the !command command will be processed, and later in the form, I will use the second part of the split string to be able to process it. Here is what I am attempting -
The splitting and reading of the message -
public void skype_MessageStatus(ChatMessage msg, TChatMessageStatus status)
{
if (msg.Body.IndexOf(trigger) == 0 && TChatMessageStatus.cmsReceived == status)
{
string command = msg.Body.Remove(0, trigger.Length).ToLower();
var splitted = command.Split(' ');
string command1 = splitted[0];
string name = splitted[1];
msg.Chat.SendMessage(nick + ProcessCommand(command1));
}
}
There are several other commands in this chat bot, so there is a switch containing different outcomes - as for !command, I have -
case "command":
result = command();
break;
And finally -
private string command()
{
WebRequest.Create("API I have" + name);
new WebClient().DownloadString("API I have" + name);
}
I would like to be able to use 'name' here, from the split message. Thanks, and any help is appreciated.
First, define the pattern you want to use to parse your inbound messages. It seems like you have multiple commands that probably have different parameters, but all commands take the following form:
![Command String] [Command Parameters]
So you will want a class that represents that:
public class ChatCommand
{
private string _command;
public string Command { get { return _command; } }
private string _parameters;
public string Parameters { get { return _parameters; } }
public ChatCommand(string command, string parameters) {
_command = command;
_parameters = parameters;
}
}
From there, you will need to adjust the method you posted to look like this. Notice that we are now telling split to stop splitting when it has 2 strings to return (basically splitting on the first space only).
public void skype_MessageStatus(ChatMessage msg, TChatMessageStatus status)
{
if (msg.Body.IndexOf(trigger) == 0 && TChatMessageStatus.cmsReceived == status)
{
string command = msg.Body.Remove(0, trigger.Length).ToLower();
var splitted = command.Split(new [] { ' ' }, 2);
var command1 = new ChatCommand(splitted[0], splitted[1])
msg.Chat.SendMessage(nick + ProcessCommand(command1));
}
}
The reason we are leaving the parameters in one string instead of splitting them out is because this gives you the flexibility to format parameters for different commands differently. For example, maybe you want to have a command to send a picture and the second parameters is a URL, or it could be JSON data or binary file data.
Now your ProcessCommand function can look like this:
public void ProcessCommand(ChatCommand command) {
switch(command.Command) {
case "command":
//I am code specific to that command and I should know what is contained in the Parameters property of the command
Console.WriteLine("Name is " + command.Parameters);
break;
}
}
Then you're done! You can add more commands with any parameters you would like.

c# Pass a multi-line string to a function and return an array

I'm new to C# programming and I'm trying to use good code practices. I know it is poor coding to use global variables in my example below, but I'm having a hard time figuring this out. So,I'm trying to accomplish two things with this question.
first of all, I am trying to figure out how to pass the text from a multi-line textbox to a function and have it return an array that I can then pass to another function for output (display/printing/saving to a file).
Second, Make my code more re-usable (by moving the globals inside the function that they are actually used in).
My question is.. How do I pass a string to a function and return an array that can then be passed to another function?
public partial class Form1 : Form
{
string[] SignalStrengthInputArray450;
string[] SignalStrengthOutputVar450 = new string[7];
// cut out other functions
private void Submit_450_Click(object sender, EventArgs e)
{
// ensure that input textbox is not null then call Load function
// SignalStrenthInput_450 is the object name of a multi-line textbox
if (!String.IsNullOrWhiteSpace(SignalStrengthInput_450.Text))
{
Load_Signal_Strength_Array();
}
else
{
// do something different
}
// additonal code for other textboxes
}
private void Load_Signal_Strength_Array()
{
// Processing Signal Strength textbox
SignalStrengthInputArray450 = SignalStrengthInput_450.Text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
foreach (string a in SignalStrengthInputArray450)
{
// loads some stuff into the SignalStrengthOutputArray450 array
}
}
}
You need a parameter and return type (string array), you may need to read more about Passing Parameters and return statement for returning values.
private string[] Load_Signal_Strength_Array(string signalStrengthInput_450)
{
string[] SignalStrengthInputArray450 = SignalStrengthInput_450.Text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
foreach (string a in SignalStrengthInputArray450)
{
// loads some stuff into the SignalStrengthOutputArray450 array
}
return SignalStrengthInputArray450;
}
Method call would be like
string[] signalStrengthArray = Load_Signal_Strength_Array(SignalStrengthInput_450.Text);
You can return array from function:
public string[] f1(string s)
{
return s.Split('/');
}
You can pass return value to anoter function:
public void f2(string[] p)
{
foreach(var item in p)
Console.WriteLine(item);
}
Use like:
public void main()
{
f2(f1("some/delimited/string");
}
Why not
have the Load_Signal_Strength_Array be a function which takes a local string as a parameter and return the reprocessed output (as array here but IList could be better)
call this function with a simple Load_Signal_Strength_Array(SignalStrengthInput_450.Text)
Example:
private string[] Load_Signal_Strength_Array(string text)
{
// Processing text
var inputs = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
var outputs = new List<string>();
foreach (string a in inputs)
{
// loads some stuff into the output array
// example:
if (!string.IsNullOrEmpty(a)) outputs.add(a);
}
return outputs.ToArray();
}

Design pattern for dynamic C# object

I have a queue that processes objects in a while loop. They are added asynchronously somewhere.. like this:
myqueue.pushback(String value);
And they are processed like this:
while(true)
{
String path = queue.pop();
if(process(path))
{
Console.WriteLine("Good!");
}
else
{
queue.pushback(path);
}
}
Now, the thing is that I'd like to modify this to support a TTL-like (time to live) flag, so the file path would be added o more than n times.
How could I do this, while keeping the bool process(String path) function signature? I don't want to modify that.
I thought about holding a map, or a list that counts how many times the process function returned false for a path and drop the path from the list at the n-th return of false. I wonder how can this be done more dynamically, and preferably I'd like the TTL to automatically decrement itself at each new addition to the process. I hope I am not talking trash.
Maybe using something like this
class JobData
{
public string path;
public short ttl;
public static implicit operator String(JobData jobData) {jobData.ttl--; return jobData.path;}
}
I like the idea of a JobData class, but there's already an answer demonstrating that, and the fact that you're working with file paths give you another possible advantage. Certain characters are not valid in file paths, and so you could choose one to use as a delimiter. The advantage here is that the queue type remains a string, and so you would not have to modify any of your existing asynchronous code. You can see a list of reserved path characters here:
http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
For our purposes, I'll use the percent (%) character. Then you can modify your code as follows, and nothing else needs to change:
const int startingTTL = 100;
const string delimiter = "%";
while(true)
{
String[] path = queue.pop().Split(delimiter.ToCharArray());
int ttl = path.Length > 1?--int.Parse(path[1]):startingTTL;
if(process(path[0]))
{
Console.WriteLine("Good!");
}
else if (ttl > 0)
{
queue.pushback(string.Format("{0}{1}{2}", path[0], delimiter,ttl));
}
else
{
Console.WriteLine("TTL expired for path: {0}" path[0]);
}
}
Again, from a pure architecture standpoint, a class with two properties is a better design... but from a practical standpoint, YAGNI: this option means you can avoid going back and changing other asynchronous code that pushes into the queue. That code still only needs to know about the strings, and will work with this unmodified.
One more thing. I want to point out that this is a fairly tight loop, prone to running away with a cpu core. Additionally, if this is the .Net queue type and your tight loop gets ahead of your asynchronous produces to empty the queue, you'll throw an exception, which would break out of the while(true) block. You can solve both issues with code like this:
while(true)
{
try
{
String[] path = queue.pop().Split(delimiter.ToCharArray());
int ttl = path.Length > 1?--int.Parse(path[1]):startingTTL;
if(process(path[0]))
{
Console.WriteLine("Good!");
}
else if (ttl > 0)
{
queue.pushback(string.Format("{0}{1}{2}", path[0], delimiter,ttl));
}
else
{
Console.WriteLine("TTL expired for path: {0}" path[0]);
}
}
catch(InvalidOperationException ex)
{
//Queue.Dequeue throws InvalidOperation if the queue is empty... sleep for a bit before trying again
Thread.Sleep(100);
}
}
If the constraint is that bool process(String path) cannot be touched/changed then put the functionality into myqueue. You can keep its public signatures of void pushback(string path) and string pop(), but internally you can track your TTL. You can either wrap the string paths in a JobData-like class that gets added to the internal queue, or you can have a secondary Dictionary keyed by path. Perhaps even something as simple as saving the last poped path and if the subsequent push is the same path you can assume it was a rejected/failed item. Also, in your pop method you can even discard a path that has been rejected too many time and internally fetch the next path so the calling code is blissfully unaware of the issue.
You could abstract/encapsulate the functionality of the "job manager". Hide the queue and implementation from the caller so you can do whatever you want without the callers caring. Something like this:
public static class JobManager
{
private static Queue<JobData> _queue;
static JobManager() { Task.Factory.StartNew(() => { StartProcessing(); }); }
public static void AddJob(string value)
{
//TODO: validate
_queue.Enqueue(new JobData(value));
}
private static StartProcessing()
{
while (true)
{
if (_queue.Count > 0)
{
JobData data = _queue.Dequeue();
if (!process(data.Path))
{
data.TTL--;
if (data.TTL > 0)
_queue.Enqueue(data);
}
}
else
{
Thread.Sleep(1000);
}
}
}
private class JobData
{
public string Path { get; set; }
public short TTL { get; set; }
public JobData(string value)
{
this.Path = value;
this.TTL = DEFAULT_TTL;
}
}
}
Then your processing loop can handle the TTL value.
Edit - Added a simple processing loop. This code isn't thread safe, but should hopefully give you an idea.

Create string in MessageBox or WriteLine

I have a question, I don't really need it for the application at the moment but I was just curious.
Is there a way to create a string and fill it between the parentheses of WriteLine or Messagebox.Show ?
The code should then look something like this I think:
MessageBox.Show(String s = string.Format("Hello World"));
That is not the correct code, my only question is: Is something like that possible?
You can declare a string inside a call like that. However you can assign it.
string s = string.Empty;
MessageBox.Show(s = string.Format("Hello World"));
If you could declare strings inside a functioncall it wouldnt be visible elsewhere. So it woulndt really make any sense having that functionality in the language.
An alternative to Evelie's answer that lets you write it all in one line could be to define a helper method returning a string:
public static string ShowMsg(string msg) {
MessageBox.Show(msg);
return msg;
}
And your code would become:
string s = ShowMsg("Hello World");
or
string s = ShowMsg(string.Format("Now is {0}.", DateTime.Now));
And you could also perform the formatting inside your helper method:
public static string ShowMsg(string format, params object[] args) {
string mgs = string.Format(format, args);
MessageBox.Show(msg);
return msg;
}
And use it as:
string s = ShowMsg("Now is {0}.", DateTime.Now);

Categories