I have a C#-Console-Program that gets called by another program.
The other Program is supposed to pass an argument to my program.
Now, in case there is no argument passed to the program, I want to make it so that the user inputs an argument into the args string array of the Main function.
I know that you can check for the length of the args string to see whether it has something in it or not like this:
if(args.Length == 0){}
But I dont seem to get it so that the user can input a new value into the console into the args array.
I already tried it like this:
if(args.Length == 0)
{
args[0] = Console.ReadLine();
}
But it only throws an error because there is the Index is out of range.
Is there a way to add an index to the args-array or any other way to handle this case? Or do I need to rewrite my code so that it doesnt take the args-Array directly but instead checks if the array has an argument in it and if not create a new array?
A better approach would be:
String username, password;
if (args.Length >= 1) username = args[0];
else username = Console.ReadLine();
if (args.Length >= 2) password = args[1];
else password = Console.ReadLine();
That way you get meaningful variables instead of a dumb array;
if (args.Length == 0)
{
// args[0] does not exist because it is an empty array.
// assign it with an new array of string instead.
args = new string[] { Console.ReadLine(), };
}
Related
So HI! I'm new to C# (started about 3 weeks ago) and have taken up some programming courses and have run in to a problem.
Here is the for loop that I'm using, and I understand that the if statement looks contrary from what I wanna achieve, but when 'if (ruckSack[i] != "")' I got the "assigned string".
Furthermore, with the current code, if I just "add" an empty string to the array the it's assigned and I understand that I give the array an empty sting as a value.
int i = container;
while (i < 5)
{
if (ruckSack[i] == "")
{
Console.WriteLine("Assigned string");
i++;
}
else
{
Console.WriteLine("Empty string");
}
ruckSack[i] = Console.ReadLine();
i++;
}
So I have a display elements of array, and delete elements from array.
So I know that everything works except for the storage-func.
I would have used a list, but the assignment asks for a string array.
How would one do to solve this?
Thanks in advance!!
Best regards
EDIT: If any one wants the whole source code, tell me and i'll add it!
If yout want to avoid that the user can type a input if there is already any string in the array, yout need to inclue the Console.ReadLine() into the else-Block.
Also, you will need to use another way to check if a string is assigned as ruckSack[i] == "" only return true if the array contains an emtpy string (""). You can use string.IsNullOrEmpty(ruckSack[i]) or string.IsNullOrWhitespace(ruckSack[i]) (last one returns also true if only space on other white-spaces are in the string).
Put together:
int i = container;
while (i < 5)
{
if (string.IsNullOrWhiteSpace(ruckSack[i]))
{
Console.WriteLine("Assigned string");
i++;
}
else
{
Console.WriteLine("Empty string");
ruckSack[i] = Console.ReadLine();
}
i++;
}
I've been trying to find a way to do this but not had much luck so far.
Basically what I'm trying to do is limit the entries from the user so they can only enter 1 letter and 1 number using the Console.Readkey. So, for example, A1, E5, J9 etc. I want to avoid them entering like 55 or EE as this causes an error in my code. Is there an easy way to achieve this?
You need to write your own logic like you will check on every input value contains at least 1 number and 1 letter is true else false:
string value = Console.ReadLine();
//you can also check value.length and redirect if length greater than 2
if (value.Length > 2)
{
Console.WriteLine("Please enter correct value");
return;
}
if (value.Contains("Your Number"))
{
if (value.Contains("Your Letter"))
{
//your code goes here
}
else
{
Console.WriteLine("Please Enter Correct Value");
}
}
else
{
Console.WriteLine("Please Enter Correct Value");
}
This uses a GetChar method which requires that you pass a function to check whether the input is a character or a number. It won't allow you so proceed until a valid entry has been made.
using System;
class Program {
public static void Main (string[] args) {
string value = string.Empty;
// Get a character, using char.IsLetter as the checking function...
GetChar(ref value, char.IsLetter);
// Get a number, using char.isNumber as the checking function...
GetChar(ref value, char.IsNumber);
Console.WriteLine($"\nValue: {value.ToUpper()}");
}
// Get a character and append it to the referenced string.
// check requires that you pass a function reference for the required check.
public static void GetChar(ref string value, Func<char, bool> check) {
// Loop until the check passes.
while(true) {
char key = Console.ReadKey(true).KeyChar;
// If check passes...
if(check(key)) {
// Append the value
value += key.ToString().ToUpper();
// Print it...
Console.Write(key.ToString().ToUpper());
// Break out of the loop.
break;
}
}
}
}
How do I go about checking the number of command line arguments entered and then printing an error if its less than 3.
static void Main(string[] args)
{
string file1 = args[0];
string file2 = args[1];
string file3 = args[2];
So if args is < 3, I need to print an erorr message and stop the program without running the next lines of code so that it doesnt give an error. Im just confused. Any help would be grealty appreciated
args is an array -- you have access to all methods related to arrays. So a simple implementation of your question could look like this:
if(args.Length < 3)
throw new ArgumentException("Must have three command line arguments");
It's almost always a good idea to ensure your variables aren't null before trying to access values on them (so the code could look like if(args == null || args.Length < 3), but per some commentary on this answer, these applications will never give you a null value for args, so it should be fine to omit that in this one specific case.
I want to do something like this:
string a = Console.Readline();
string[] b = a.Split(' ');
string i = b[0];
string j = b[1];
Now the problem is, putting the 'string j' may be optional like the input may be hi hello here hello is optional. How to make the code work if someone doesn't put something in place of hello.
Thanks in advance.
You could use the Length property to check how many elements are in the split array.
If there are not enough elements in the array to assign the optional value you can set it to null.
In the rest of your code you just have to null-check the optional value before using it.
Something liket his would work:
string input = Console.ReadLine();
string[] tokens = input.Split(' ');
string hi = tokens[0];
string optional = tokens.Length > 1 ? tokens[1] : null; // make sure we have enough elements
Console.WriteLine(hi);
// null check before using the optional value
if (optional != null)
Console.WriteLine(optional);
// or
Console.WriteLine(optional ?? "Optional value is null..");
Instead of accessing the arrays particular element by its index position, I would use foreach loop to iterate over a list like:
string a = Console.ReadLine();
string[] b = a.Split(' ');
foreach (string elem in b)
{
Console.WriteLine(elem); // Do whatever you want with each element
}
Console.ReadLine();
Since the "commands" entered by the user will be stored in the array (e.g. b based on your code) after the split, I don't think it's necessary to store them in individual variables yourself. Thus, avoiding the problem you have in your current setup. On the other hand, if you want to see if a specific "command" was keyed in, you can do something like this:
static void Main(string[] args)
{
Console.Write("> ");
string input = Console.ReadLine();
// Doing it like this will automatically remove blanks from the resulting array
// so you won't have to clean it up yourself
string[] commands = input.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
// Contains is from the System.Linq namespace
// this will allow you to see if a given value is in the array
if (commands.Contains("hi"))
{
Console.WriteLine("> The command 'hi' has been received.");
}
Console.Read();
}
You can use Linq's Contains method to check if a specific value exists in the array of command strings.
if you just want to see all the commands in the array, a simple for loop would be enough.
// The Length property of the array will give you the
// number of items it contains
for(int i = 0; i < commands.Length; i++)
{
Console.WriteLine("> Command read: {0} ", commands[i]);
}
One more thing, I suggest that you normalize the inputs your application will receive as to avoid problems when filtering through them. You could do this by calling the ToLower method available to ReadLine:
string inputs = Console.ReadLine().ToLower();
Happy coding :)
I have a (hopefully) simple C# question.
I am parsing arguments in a program where a file will be read from command line, I've allowed for both short and long arguments as input (so for my scenario /f and file are both valid)
The value after either of the above arguments should be the file name to be read.
What I want to do is find this file name in the array based off whichever argument is chosen and copy it in to a string while not leaving any loopholes.
I have functioning code, but I'm not really sure it's "efficient" (and secure).
Code (comments and writes removed):
if ( args.Contains("/f") || args.Contains("file"))
{
int pos = Array.IndexOf(args, "/f");
if (pos == -1)
pos = Array.IndexOf(args, "file");
if (pos > -1)
pos++;
inputFile = (args[pos]);
if (File.Exists(inputFile) == false)
{
Environment.Exit(0);
}
}
Is there a more efficient way to do this, perhaps using some nifty logic in the initial if statement to check which parameter is valid and then do a single check on that parameter?
Using 4 ifs and 2 Array.IndexOf's seems horrible just to support 2 different ways to allow someone to say they want to input a file...
Thanks! And I'm sorry if this seems trivial or is not what SO is meant for. I just don't have any real way to get feedback on my coding practises unfortunately.
Your solution won't scale well. Imagine you have two different arguments with a short and long form. How many conditionals and index checks would that be?
You'd be better off using an existing tool (e.g. Command Line Parser Library) for argument parsing.
One problem I see with the code you provided is that, it will fail if the /f or file is the last argument.
If you don't want to write or use complete argument parsing code, the following code will work slightly better.
var fileArguments = new string[] { "/f", "file" };
int fileArgIndex = Array.FindIndex(args,
arg => fileArguments.Contains(arg.ToLowerInvariant()));
if (fileArgIndex != -1 && fileArgIndex < args.Length - 1)
{
inputFile = args[fileArgIndex + 1];
if (!File.Exists(inputFile))
{
Environment.Exit(0);
}
}
You could write a simple argument parser for your specific need and still have support for "new" scenarios. For example, in your entry method have
// The main entry point for the application.
[STAThread]
static void Main(string[] args)
{
// Parse input args
var parser = new InputArgumentsParser();
parser.Parse(args);
....
}
Where your InputArgumentsParser could be something similar to
public class InputArgumentsParser
{
private const char ArgSeparator = ':';
private Dictionary<string[],Action<string>> ArgAction =
new Dictionary<string[],Action<string>>();
public InputArgumentsParser()
{
// Supported actions to take, based on args
ArgAction.Add(new[] { "/f", "/file" }, (param) =>
Console.WriteLine(#"Received file argument '{0}'", param));
}
/// Parse collection, expected format is "<key>:<value>"
public void Parse(ICollection<string> args)
{
if (args == null || !args.Any())
return;
// Iterate over arguments, extract key/value pairs
foreach (string arg in args)
{
string[] parts = arg.Split(ArgSeparator);
if (parts.Length != 2)
continue;
// Find related action and execute if found
var action = ArgAction.Keys.Where(key =>
key.Contains(parts[0].ToLowerInvariant()))
.Select(key => ArgAction[key]).SingleOrDefault();
if (action != null)
action.Invoke(parts[1]);
else
Console.WriteLine(#"No action for argument '{0}'", arg);
}
}
}
In this case /f:myfile.txt or /file:myfile.txt would spit out to console
Received file argument 'myfile.txt'