I am having trouble getting a method working and I am not sure I am doing it the correct way. What I want to do is to send a string from a form by a button_click into a class and process it there for errors(tryparse method) and the send a boolvalue back to then either report and error to the user or to print input in an listbox.
This is the form code I have that is supposed to send the string into the class.
private void btnOK_Click(object sender, EventArgs e)
{
Errorcheck.GetDouble(numChoice);
}
and then the Errorcheck class:
public static bool GetDouble(string numChoice, out double value, double minLimit, double maxLimit)
{
while (!double.TryParse(numChoice, out value))
{
if ((value >= minLimit) && (value <= maxLimit))
{
return true;
}
}
return false;
}
How do I retrieve the bool value from the Errorcheck class? if it was ok or not. Am I doing the right way or is there a quicker way to go about it?
private void btnOK_Click(object sender, EventArgs e)
{
double foo;
var myresult = Errorcheck.GetDouble(numChoice, out foo, 1, 2);
//When myresult == true, foo contains the parsed value
}
myresult will contain the result returned by GetDouble either true (value could be parsed and is within limits) or false (value could be parsed but was out of limits or failed to parse in the first place). Also, foo will contain 0 if parsing failed, otherwise the parsed value (which, may or may not!) be within the limits.
I do, however, have some problems with your code. First; why is your class named Errorcheck while, in fact, it doesn't do error-checking (what is that anyway?) but parse a value.
Second, why use the while() construct?
public static bool GetDouble(string numChoice, out double value, double minLimit, double maxLimit)
{
return double.TryParse(numChoice, out value)
&& ((value >= minLimit) && (value <= maxLimit));
}
Third; GetDouble() doesn't actually "get" a "double". It checks if a value is parseable as a double and, if so, is within bounds. It returns a bool for Pete's sake.
EDIT Scratch that; I missed the out on the method signature. It returns a bool and also the value.
...and then some more but I might be nitpicking :P
And, last but not least, I don't see what this has to do with "how bool values and variables get sent between classes/forms"?
Take my, well intended, advice and get a good C# or general book on programming and brush up your basic skills a little. You will only benefit and soon you'll see why your code is, no flame intended, "bad" in many ways.
I would do it like that:
private void btnOK_Click(object sender, EventArgs e)
{
double parsedValue;
if (Errorcheck.IsDoubleBetween(numChoice, out parsedValue, maxValue, minValue))
{
//Your code here
}
}
Errorcheck code:
public static bool IsDoubleBetween(string numChoice, out double value, double minLimit, double maxLimit)
{
bool result = double.TryParse(numChoice, out value) && (value >= minLimit) && (value <= maxLimit);
return result;
}
As you can see, there are a few changes:
The name IsDoubleBetween explains the method logic.
There is a call to IsDoubleBetween with the right parameters.
There is a use of IsDoubleBetween return value.
IsDoubleBetween code is more readable.
In this case i would try to separate the two operations of IsDoubleBetween to two methods so there will be single responsibility to each - parsing and checking between value
Related
I have many methods which are very similar as shown in the code below:
public static void ReadFromKeyboard(string label, out int retVal)
{
try
{
Console.Write(label);
retVal = int.Parse(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("Please insert int value.");
ReadFromKeyboard(label, out retVal);
}
}
public static void ReadFromKeyboard(string label, out float retVal)
{
try
{
Console.Write(label);
retVal = float.Parse(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("Please insert float value.");
ReadFromKeyboard(label, out retVal);
}
}
public static void ReadFromKeyboard(string label, out double retVal)
{
try
{
Console.Write(label);
retVal = double.Parse(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("Please insert double value.");
ReadFromKeyboard(label, out retVal);
}
}
By the other hand, I don't know which method I will call. I'll discorver it only at runtime.
Is there any way I could rewrite these many methods into a single method named something like "ReadFromKeyboard" which returns either an int, a float or a double depending on the type which is passed to it as a parameter?
Thank you!
As other answers have shown, you can eliminate the duplicated code by a variety of techniques, all of which are horrible and you should not do them.
In particular, do not attempt to use generics to solve this "problem". Generics are for situations where the code is generic. That is why they are called generics! That is, the code operates the same on every possible type. Your example is the opposite of generic code; you have different rules for a small number of types, and the way to handle that situation is to do exactly what you have already done: implement one method per different rule.
I say "problem" in quotes because you do not actually have a problem to solve here, so stop trying to solve it. Writing half a dozen similar short methods is not a major burden on authors or maintainers.
Now, that said, your code is also not as good as it could be and you should rewrite it. The correct way to write your code is:
public static int ReadInteger(string label)
{
while(true)
{
int value;
Console.Write(label);
string read = Console.ReadLine();
bool success = int.TryParse(read, out value);
if (success)
return value;
Console.WriteLine("Please type an integer value.");
}
}
The problems with your original implementation are:
Do not use exception handling as mainline control flow. Do not catch an exception if the exception can be avoided. That's what TryParse is for.
Do not use recursion as unbounded looping. If you want an unbounded loop, that's what while(true) is for. Remember, C# is not tail recursive by default!
Do not use out parameters without need. The method logically returns an integer, so actually return an integer. Rename it so that you do not get collisions with other read methods. There is no compelling benefit to making the caller write Read<int> over ReadInteger, and many compelling benefits to avoiding the out param.
I've tried to implement the code according to Eric Lippert recipes. The code below
does not use exception handling as mainline control flow
does not use recursion at all
does not use output parameters without need
.
private static void Main(string[] args)
{
int intValue = ReadFromKeyboardInt32("enter int");
float floatValue = ReadFromKeyboardSingle("enter float");
double doubleValue = ReadFromKeyboardDouble("enter double");
Console.WriteLine($"{intValue}, {floatValue}, {doubleValue}");
}
public static Double ReadFromKeyboardDouble(string label) =>
ReadFromKeyboard(label, (text) => (Double.TryParse(text, out var value), value));
public static Int32 ReadFromKeyboardInt32(string label) =>
ReadFromKeyboard(label, (text) => (Int32.TryParse(text, out var value), value));
public static Single ReadFromKeyboardSingle(string label) =>
ReadFromKeyboard(label, (text) => (Single.TryParse(text, out var value), value));
public static T ReadFromKeyboard<T>(string label, Func<string, (bool, T)> tryParse)
{
for (; ; )
{
Console.Write($"{label}: ");
var result = tryParse(Console.ReadLine());
if (result.Item1)
{
return result.Item2;
}
Console.WriteLine($"Please enter valid {typeof(T).Name} value");
}
}
Instead of listing all the possible types (which you might not know beforehand), it is possible to use the System.Convert class, specially the Convert.ChangeType() method. As a proof of concept you can use a method like this:
public static void ReadFromKeyboard<T>(string label, out T result) {
Type targetType = typeof(T);
Console.Write($"{label}: ");
string input = Console.ReadLine();
object convertedValue = Convert.ChangeType(input, targetType);
result = (T)convertedValue;
}
You can use this method like this:
public static void Main(string[] args) {
ReadFromKeyboard("enter a double", out double d);
ReadFromKeyboard("enter an int", out int i);
Console.WriteLine($"double: {d}");
Console.WriteLine($"int: {i}");
}
This way it is possible to use any type you want (assuming it is supported by the Convert class). Obviously you can add exception handling and a do-while loop in the ReadFromKeyboard method if you like.
If you want to rely on overload resolution for the runtime to decide which method to call, then you must have a separate method for each type you will support. That's how it works.
On the other hand, if you can allow the user to supply at least a little type information, we can improve things a bit with generics by removing try/catch and using a real return statement. You'd call it like this:
var myNumber = ReadFromKeyboard<double>("Enter a double: ");
And the code would look like this:
public static T ReadFromKeyboard<T>(string label, int maxRetries = int.MaxValue)
{
while (maxRetries >= 0)
{
Console.Write(label);
if (typeof(T) == typeof(int))
{
int result;
if (int.TryParse(Console.ReadLine(), out result)) return (T)(object)result;
}
if (typeof(T) == typeof(float))
{
float result;
if (float.TryParse(Console.ReadLine(), out result)) return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
double result;
if (double.TryParse(Console.ReadLine(), out result)) return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
decimal result;
if (decimal.TryParse(Console.ReadLine(), out result)) return (T)(object)result;
}
else
throw new InvalidOperationException("Unsupported type");
maxRetries--;
}
throw new InvalidOperationException("Too many bad inputs");
}
But you have to do some really janky casting and type checking to make it work. There is still a potential this can throw an exception, which it seems like you want to avoid, but if your user sits there for more than 2 billion attempts, I doubt they'll be very surprised.
private bool DataValidation(string Checker)
{
int i;
if (Int32.TryParse(Checker, out i))
{
return true;
}
else
{
return false;
}
}
private void NumberChecker()
{
if (int.Parse(txtRank.Text) >= 0 || int.Parse(txtRank.Text) <= 50)
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
else
{
errorProvider1.SetError(txtRank, "Between 1 and 50 please!");
}
}
private void txtRank_Validating(object sender, CancelEventArgs e)
{
if (DataValidation(txtRank.Text) == false)
{
errorProvider1.SetError(txtRank, "Must be numeric!");
}
else
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
NumberChecker();
}
I've been trying to get this to work for about 4 hours, can someone please tell me why it keeps saying "String in the wrong format" I've tried all of this inside the the validation event, nothing I do is working. I am not understanding why.
Update:
private void txtRank_Validating(object sender, CancelEventArgs e)
{
if (DataValidation(txtRank.Text) == false)
{
errorProvider1.SetError(txtRank, "Must be numeric!");
}
else
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
if (Convert.ToInt32(txtRank.Text) >= 0 && Convert.ToInt32(txtRank.Text) <= 50)
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
else
{
errorProvider1.SetError(txtRank, "Between 1 and 50 please!");
}
}
if i use the code above, i can either do one or the other, but i have to comment out a section of code in order to do that.
You're doing a lot of stuff here that isn't necessary at all.
First off: Assuming that the if statement in your DataValidation method is only intended to have the return true and return false, the if statement is totally unnecessary. You could just say return Int32.TryParse(Checker, out i); and it would do the exact same thing. In fact, you could remove the int i in the first place, and just do this:
private bool DataValidation(string Checker) {
return Int32.TryParse(Checker, out int i);
}
out int i creates a temporary variable... and since the DataValidation method is now a single method call, you may realize that the whole method is now unnecessary. You could simply replace any call to DataValidation(someString) with Int32.TryParse(someString, out int i) with no side effects.
Moving on to your NumberChecker method, the error becomes immediately apparent:
if (int.Parse(txtRank.Text) >= 0 || int.Parse(txtRank.Text) <= 50)
This is the only place in your code where you are parsing a string without checking to ensure that it's a number first. Evidently, txtRank.Text is a string that is not a proper number. This is actually where TryParse would come in handy.
I'm going to assume that you don't know exactly what TryParse does and that you were only using it as an error checker, which is okay, because the function of out arguments aren't immediately apparent.
The out keyword, effectively, allows a function to change the thing that was passed in. Take the following code snippet:
public static void Main(string[] args)
{
String foo = "abc";
DoSomething(out foo);
Console.WriteLine(foo);
}
private static void DoSomething(out String something)
{
something = "def";
}
Despite DoSomething not returning a value, the Console.WriteLine(foo); will write def rather than abc. Int32.TryParse uses this to its advantage: It returns a bool that says whether the operation was successful or not. And if it was successful, it stores the result in the variable used as the out argument.
As such, your NumberChecker method should look something like this:
private void NumberChecker()
{
int num = null;
if (Int32.TryParse(txtRank.Text, out num) {
// if TryParse returns true, then we have a result in `num`.
if (num >= 0 && num <= 50)
{
errorProvider1.SetError(txtRank, string.Empty);
errorProvider1.Clear();
}
else // txtRank.Text is a number, but is not within the range
{
errorProvider1.SetError(txtRank, "Between 1 and 50 please!");
}
}
else // txtRank.Text is not a number to begin with
{
errorProvider1.SetError(txtRank, "txtRank.Text is not a number!");
}
}
Worth noting: Since NumberChecker() can now handle the case of invalid text like txtRank_Validating() used to, you can now remove txtRank_Validating() as well. NumberChecker() is now the only necessary code.
One final thing worth noting: In your original code, although your txtRank_Validating() has if statements for in case txtRank.Text was not a number, the reason it was still failing was because NumberChecker() was called at the end of the method whether the text was a number or not. In that sense, the easiest solution would have just been to move the NumberChecker(); call to after errorProvider1.Clear(); inside the else block. But I think the rest of the details in this answer are worth taking note of.
I'm trying to make a method such as this
public static bool GetInteger(string stringToConvert, out int intOutValue, int minLimit, int maxLimit)
I want it to check if the value is within the min and max range that I specify with the in-values. The parsing is just
int.TryParse(stringToConvert, out intOutValue)
but how do I now check if the value of "intOutValue" is within range? It keeps telling me that it is a bool-value...
Any help on how to do this would be greatly appriciated! (I'm pretty new to programming, and especially in c#)
If you're trying to do comparisons based on the result of the call to TryParse then therein lies your problem; that returns a boolean to indicate success or not (hence the Try). So you need to compare the inOutValue as that's what has been populated.
public static bool GetInteger(string input, out int result, int min, int max) {
return int.TryParse(input, out result) && (result >= min && result <= max);
}
There is no need for an out param here, and I'd even say the method naming is bad, unless you actually want the value to be accessible after the fact.
It looks like you want to check if it is also in the given range, as well as a valid int. In which case you could do:
public static bool GetInteger(string stringToConvert, out int intOutValue, int minLimit, int maxLimit)
{
bool parsed = int.TryParse(stringToConvert, out intOutValue);
return parsed && intOutValue >= minLimit && intOutValue <= maxLimit;
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
If I write a = a +115 my MessageBox will return 215 but if write like a=115; it will display 115.
Why is that?
private void button1_Click(object sender, EventArgs e)
{
int c=100;
MessageBox.Show(Count(c).ToString());
}
public int Count(int a)
{
a=115;
return a;
}
The question is very hard to decipher. I think that you have tried two different versions of the function that you named Count, as shown below.
Consider this version of the function:
public int Count1(int a)
{
a = 115;
return a;
}
It returns 115 no matter what value you pass as the parameter. You are overwriting the parameter with the assignment a = 115. The parameter is therefore utterly pointless.
And now the other version:
public int Count2(int a)
{
a = a + 115;
return a;
}
This version of the function receives a parameter in the variable a. It then adds on 115 to that value, and returns the result. So when you call it like this:
Count2(100)
the value that is returned is 215.
It might be easier to understand if you wrote the functions like this:
public int Count1(int a)
{
return 115; //very clearly the input parameter is ignored
}
public int Count2(int a)
{
return a + 115; //but in this version, the input parameter is used
}
These versions are exactly equivalent to your versions but I hope you'll find them easier to understand.
Here are three versions of your code to demonstrate what is going on, and what I think you're really asking:
Original:
private void button1_Click(object sender, EventArgs e)
{
// Set c to 100
int c=100;
// Print the result of Count, which (see below) is ALWAYS 115.
MessageBox.Show(Count(c).ToString());
}
public int Count(int a)
{
// Set a to 115 (there is no add here, I think this is a typo)
a=115;
// Return a, which is ALWAYS 115.
return a;
}
What I think you meant:
private void button1_Click(object sender, EventArgs e)
{
// Set c to 100
int c=100;
// Print the result of Count, which will be 215.
MessageBox.Show(Count(c).ToString());
}
public int Count(int a)
{
// Add 115 to a.
a+=115;
// Return the result (if a == 100, this will return 215)
return a;
}
What I think you're getting at:
private void button1_Click(object sender, EventArgs e)
{
// Set c to 100
int c=100;
// Call the count function, passing in a reference for c.
Count(ref c);
// Print the value of c. This will be 215 because the Count function set c to a new value.
MessageBox.Show(c.ToString());
}
public void Count(ref int a)
{
a+=115;
}
In this last case, I changed the function to public void Count(ref int a). The ref modifier allows the function to assign a new value using a reference to another variable. Normally, parameters are "by value", where a copy of the variable's value is passed in.
Note that the second version would be preferred in this case. By reference parameters should only be used when they are truly necessary, not as a replacement for a simple return value.
a = 115 sets an integer variable to 115, a += 115 or a = a + 115 will add 115 to the value for a and then you are returning the result of that value
if you pass 100 to function which has statement a = a + 115 which is a = 100 + 115 then it should return 215
public int Count(int a)
{
a = a + 115; // a = 100 + 115
return a;
}
When you do a=115, it displays 115 because you're ASSIGNING 115 to a. When you use the =, you're ASSIGNING the right value to the left value. Much the same you're doing when you do int c=100. You're assigning c to be 100.
When you pass in c, c is 100, and your formula is a=a+115, then a will be 215. When you pass in a value like you're doing, a will be 100. So, when you do your formula of a=a+115, you're saying a=100+115, and you'll get the 215.
Is the confusion because you think "a" and "c" are separate values?
The method Count(int a) doesn't care that the name of the value was
originally "c". Once it is inside of that method, it will be referred
to only as "a."
public int Count(int a)
{
a = a+115;
return a;
}
So step-by-step:
1) You pass the value 100 to the Count() method. (a = 100)
2) Count() sets the value of a to 100 + 115. (a = 215)
3) 215 is returned back to your calling method.
4) Your calling method displays 215 as a string.
Does that help?
Your Count() method just throws away the value it was passed and returns 115. If you replace a=115 with a=a+115, and pass it 100, it will return 215. This is all as expected.
a=a+115 means "take the value of a, add 115 to it, and assign the total to a."
This is all working as expected.
It looks like you're wondering how the variable a translates to your message box. This is because the variable a is in your count() function. Changing its value changes the result of the count function. And since your message box gets its value from count, there you have it.
I'm not quite sure how to ask my question in C# terms, so please bear with the long-winded explanation.
I'm writing a stock trading algorithm. When the algo starts, it checks to see what kind of instrument it is applied to (in this case, either stock or futures), and then depending on the instrument, assigns a value to "double x".
If its a future instrument, then the assignment is a simple, flat value (in this case, "double x = 5;). However, if its a stock, I'd like "x" to be assigned to a value from another object - lets call the object "Algo2" and the value "y". So, in my script the assignment is as follows: "double x = Algo2.y" (note: that's the convention in the editor I'm using). This block of code is run only once when the algorithm begins.
What I'm trying to achieve here is to tell my algorithm to get the latest value of "Algo2.y" whenever "x" is used in a formula such as "EntryValue = Price + x". However, whats happening is that "x" is permanently assigned the value of "Algo2.y" at the start of the program, and since that block is never run again, remains that constant value throughout.
Can anyone help with the syntax so that instead of assigning a value to "x", it simply points to get the latest value of "Algo2.y" whevever it's called?
Thanks!
Make 'x' a property, so that it fetches the value each time you ask for x.
class StockInstrument
{
public double Value //x isn't a good name, I'll use "Value"
{
get
{
if(...) return 5.0;
else return Algo2.y;
}
}
}
Write a function for it:
double getAlgo2YValue()
{
return Algo2.y; // or Algo2.getY(), another function if you can't access it
}
In your main algorithm, now call:
x = getAlgo2YValue();
To update X.
I would use a method to return your latest value
public double GetXValue()
{
if (AlgoType == Algos.Futures)
{
return 5.0;
}
else if (AlgoType == Algos.Stock)
{
return Algo2.y;
}
//else
throw new Exception("unknown algo type");
}
This is quite hard coded, but it could be cleaned up using delegates and encapsulation of the algorithms, but at a low level - this is the idea. Also, some people prefer to use properties for this - Just don't use properties when the get has modifying affects
public double X
{
get
{
if (AlgoType == Algos.Futures)
{
return 5.0;
}
else if (AlgoType == Algos.Stock)
{
return Algo2.y;
}
//else
throw new Exception("unknown algo type");
}
}
May use something like:
double X {
get {
if(isStock())
return Algo2.y;
else
return 5;
}
}
Func<int> getX;
if(isFuture)
getX = () => 5;
else
getX = () => Algo.y;
// using getX() will always return the current value of Algo.y,
// in case it's a stock.
int xval = getX();
Give Algo2 a reference to Algo so that no 'double X' copy is needed. Algo can then dereference the actual value in Algo2 at any time, (thread-safety an issue?).
Value data types, such as int are always going to be copied by value, not as a reference. However, what you can do is architect your solution a little differently, and then it will provide the right value. For example:
public class ValueContainer
{
protected Algo2 _reference = null;
protected double _staticValue = 0;
public double CurrentValue
{
get
{
if(_reference == null)
return _staticValue;
return _reference.y;
}
}
public ValueContainer(Algo2 reference)
{
_reference = reference;
}
public ValueContainer(double value)
{
_staticValue = value;
}
}
Then, you replace your x with the ValueContainer instance wherever needed and use the CurrentValue property to get the value. You create each version with a different constructor then:
ValueContainer container = null;
if(stock)
container = new ValueContainer(5);
else
container = new ValueContainer(Algo2);
What you need is a property wrapper for x to control the value that's returned, based on the instrument type. Here's an example, which will require some significant adaptation for your app.
public class Instrument
{
// an example enum holding types
public InstrumentType Type {get; set;}
// x is not a great name, but following your question's convention...
public double X
{
get
{
if(type == InstrumentType.Stock)
return Algo2.y();
// note that I changed this to be a method rather than a property
// Algo2.y() should be static so it can be called without an instance
else if(type == InstrumentType.Future)
return 5.0;
else
// return some default value here
}
}
}