Too many methods very similar - c#

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.

Related

Cannot implicitly convert type to string

So, I have some code that I am working on (not a dev, but we deal with the hand that we have been dealt) and I have a small, but frustrating error that is popping up, after I have struggled my way through the rest of the issues. In this code:
public class ObservableCollection<ReportData>
{
public string GetQueryData(string date, string ip, string query)
{
ObservableCollection<ReportData> result = new ObservableCollection<ReportData>();
try
{
var data = GetRemoteQueryJournal(ip, date, query);
if (data != null)
{
result = GetReporData(data);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.StackTrace);
}
return result;
}
}
If the class only gets strings, shouldn't the return BE a string? But I get
A C# (or any programming language) function has a standard definition, which looks like this:
return_type FunctionName (parameter1_type parameter1_name, parameter2_type parameter2_name,...)
{
}
Parameters are optional
Return type can be void, in which case you don't need to return anything.
For all other return types, you need to return a value matching the return type.
So let's take a very simple function, which takes in two ints as parameters, adds them up, and return the sum as an int. It would look like this:
int AddTwoInts(int a, int b)
{
int sum = a + b;
return sum;
}
The return type is int, and the sum is also int so it works fine.
Say you want to add two ints but return the sum as a string for whatever the reason. Then your function definition would have to look like this:
string AddTwoIntsAndReturnAsString(int a, int b)
{
// function body
}
However, in this case, if you had the same function body as before, the compiler will complain:
string AddTwoIntsAndReturnAsString(int a, int b)
{
int sum = a + b;
return sum;
}
Because sum is still and int but the function wants you to return a string, which is a conflict and the compiler doesn't like that. So it will complain. You can fix this by matching what you return to actual return type.
static string AddTwoIntsAndReturnAsString(int a, int b)
{
int sum = a + b;
return sum.ToString();
}
Now this will get rid of the error, but doesn't necessarily mean that'll fix all problems. Typically if you add two numbers you want the result to be a numeric type where you can do additional calculations later on. So for a function that adds two numbers it makes more sense to actually return an int, not a string.
Similarly in your case, your result is of type ObservableCollection<ReportData>. An ObservableCollection is essentially a list. So converting it into a string and returning just to get rid of the error doesn't make sense, as the function wants to return the above type in order to get some work done later on.
So it'll make more sense to change your function's return type:
public ObservableCollection<ReportData> GetQueryData(string date, string ip, string query)
{
ObservableCollection<ReportData> result = new ObservableCollection<ReportData>();
try
{
var data = GetRemoteQueryJournal(ip, date, query);
if (data != null)
{
result = GetReporData(data);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.StackTrace);
}
return result;
}
Try this in your return statement
return result.ToString();
or maybe you want
return result != null ? "It worked":"It failed";
That should make the issue clear. You say this function returns a string but you are returning a different object type.
You will have to change the return type from string to ObservableCollection<ReportData> or ReportData (depending on your needs).
If you do this and the class only gets strings as you phrased it, then yes the result will be strings. This is how generics works.

How can I handle an exception in C#? [duplicate]

This question already has answers here:
Parse v. TryParse
(8 answers)
Closed 5 years ago.
I'm trying to handle an exception to avoid my program crash if double.Parse(string) tries parsing invalid values (such as strings instead of numbers). Here's what I've got:
do
{
//asking customer the amount of shirts he would like to buy any shirts they want.
numbershirtString = Console.ReadLine(); // customer types in amount of shirts they want.
numbershirts = double.Parse(numbershirtString);
keepLooping = true;
if (numbershirts < 10)
{
Console.WriteLine("You would be buying " + numbershirts + " shirts");
keepLooping = false;
}
if (numbershirts > 10)
{
Console.WriteLine("You cannot order more than 10 shirts. Please try again.");
keepLooping = true;
}
} while (keepLooping);
I would appreciate your help. Thank you in advance!
Use double.TryParse() instead. It returns true of false depending on the outcome:
double val;
bool success = double.TryParse("red", out val);
if(success)
{
// val contains a parsed value
}
else
{
// could not parse
}
To handle an exception, in C# like similar in other languages, you can use the try..catch block.
Look at the simplest syntax:
try
{
//Try to run some code.
}
catch
{
//Do something if anything excepted.
}
If you're interested to retrieve which exception breaked the code:
try
{
//Try to run some code.
}
catch (Exception ex)
{
//Do something ex was thrown.
}
If you change the type of ex to something inheriting the base class Exception you'll handle only all the exception of that type:
try
{
//Try to run some code.
}
catch (StackOverflowException ex)
{
//Do something ex was thrown because you overflowed the stack.
}
But instead of talking about try..catch block which you can find out more about on Google, I suggest you to use the method double.TryParse(string, out double).
Its syntax is a little bit different than double.Parse, but effectively it does the same in a different way.
It returns true if your input is valid, else it returns false, whereas in the first parameter you have just to pass your string input and in the second one is required an output reference to the result variable:
double x = 0;
string number = "125.3";
if (double.TryParse(number, out x))
Console.WriteLine("Your number is " + x.ToString());
else
Console.WriteLine("Your input isn't valid");
Maybe this is a little advanced for you, but if you are feeling in a clever mood, you can define a class that handles the parsing of user input. That way you can keep that logic separated from your main program (see separation of concerns).
public class UserEntry
{
private readonly string _originalValue;
public UserEntry(string input)
{
_originalValue = input;
}
public bool IsInt
{
get
{
return int.TryParse(_originalValue, out var dummy);
}
}
public int ToInt()
{
return ToInt(default(int));
}
public int ToInt(int defaultValue)
{
int result;
bool ok = int.TryParse(_originalValue, out result);
return ok ? result : defaultValue;
}
public override string ToString()
{
return _originalValue;
}
static public implicit operator UserEntry(string input)
{
return new UserEntry(input);
}
static public implicit operator Int32(UserEntry input)
{
return input.ToInt();
}
}
If we use implicit conversion operators it makes things very simple. For example, all of these are now legal:
UserEntry entry = Console.ReadLine();
if (!entry.IsInt) continue;
if (entry < 10) return entry;
If we apply this to your example, it shortens your code a bit, and arguably makes it a bit clearer as well.
public class Program
{
private const int MaximumOrder = 10;
public static void Main()
{
var n = AskForNumberOfShirts();
Console.WriteLine("OK, I'll order {0} shirts.", n);
}
public static int AskForNumberOfShirts()
{
while (true)
{
Console.WriteLine("Enter the number of shirts to order:");
UserEntry entry = Console.ReadLine();
if (!entry.IsInt)
{
Console.WriteLine("You entered an invalid number.");
continue;
}
if (entry > MaximumOrder)
{
Console.WriteLine("{0} is too many! Please enter {1} or fewer.", entry, MaximumOrder);
continue;
}
return entry;
}
}
}
Notes:
I doubt you can order half a shirt, so I am using an int instead of a double to store the number of shirts.
I refactored the logic branches to use opportunistic return, a.ka. Guard Pattern. See this article for why I do this.
I extracted the constant value 10 to its own symbol, MaximumOrder. This should get you a couple points on the assignment.
Output:
Enter the number of shirts to order:
22
22 is too many! Please enter 10 or fewer.
Enter the number of shirts to order:
sdlfkj
You entered an invalid number.
Enter the number of shirts to order:
9
OK, I'll order 9 shirts.
Working example on DotNetFiddle

C# Assigning a variable from a different object

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
}
}
}

check for valid number input - console application

I have a little problem with a simple console application in which i would like to detect if the user inputs a correctly formatted numerical value.
That is, values such as 1212sss or anything like asjkq12323 or a single character is not accepted. I would like to only accept pure integer values.
Here is what i have tried
bool detectNumber(string s)
{
int value=0;
Int.TryParse(s,out value);
return (value!=0)?true:false;
}
I appreciate any help. Thank you soooo much,,,,,
TryParse returns a boolean. Check that, not the value passed via the out parameter.
if( int.TryParse( s, out value ) )
{
// do something
}
Or just:
return int.TryParse( s, out value );
Incidentally, it is not necessary to initialize a value passed using the out keyword. The method declaring the parameter must initialize it before returning.
int foo; // legal
int.TryParse( "123", out foo );
All BCL "Try" methods follow the same convention (such as double.TryParse() for floating point numbers, as #gdoron mentioned in the comments).
And for the curious, source code for the underlying library which implements int.TryParse().
int value = 0;
bool ok = int.TryParse(s, out value);
return ok;
string line = Console.ReadLine();
int value;
if (int.TryParse(line, out value))
{
Console.WriteLine("Integer here!");
}
else
{
Console.WriteLine("Not an integer!");
}
There are several ways to test for only numeric numbers:
first of all, never use Int because of it's maximum value, either use int or Int32.
Parse
int result;
if (int.TryParse("123", out result))
{
Debug.WriteLine("Valid integer: " + result);
}
else
{
Debug.WriteLine("Not a valid integer");
}
Convert.ToInt32()
// throws ArgumentNullExceptionint
result1 = Int32.Parse(null);
// doesn't throw an exception, returns 0
int result2 = Convert.ToInt32(null);
IsNumeric()
using Microsoft.VisualBasic;
// ......
bool result = Information.IsNumeric("123");
Pattern Matching
string strToTest = "123";
Regex reNum = new Regex(#"^\d+$");
bool isNumeric = reNum.Match(strToTest).Success;
Your code works normal, you can only refactor it a bit. Following code is shorter but does exactly the same:
static bool IsInt32(string s)
{
int value;
return Int32.TryParse(s, out value);
}

method return types

I'm new to C# and I'm trying to figure out the best way to test if a method returns correctly, ie; did the method get the information I wanted.
It's the types that are making this difficult. Is there a way that I can sometimes return bool and sometimes return something else?
In PHP I would create my function like this
function myFunc(){
//Do Stuff
if(/*whatever*/) return (string) "abcdefg";
return false; //otherwise it will just return false
}
Then call it like this to test if it worked or not
if(!$var=myFunc()) die("It Didn't Work");
echo $var;
But with C#, my function has to return a specified type, not a string or bool false if it didn't work out.
If in C# I have a method that returns IntPtr I could have it return (IntPtr) 0 instead of false, but this is messy and there's probably a better way of doing it.
Any Ideas? What's the standard and usual way of doing this in C#?
There are typically two approaches here:
Use Exceptions
Use the TryXXX approach.
The appropriate method depends on what this is doing. If the "false" case is really something that's exceptional and not the norm, raising an exception is an appropriate way of handling it.
If, however, you're doing something like parsing user input, where its common that you'll "fail", using the TryXXX approach is a good example. This would look like:
bool TryMyFunc(out string result)
{
if (...)
{
result = "abcdefg";
return true;
}
result = string.Empty;
return false;
}
This is how Int32.TryParse works in the framework, for example.
You can always return null.
string Foo()
{
if (!success) return null;
return "abcd";
}
You then check the call like that:
var tmp = Foo();
if (tmp == null) return -1;
// tmp is a string so do your work
The null return will only work with object, unfortunately you can't do that with an int. In that case throw an exception or use a nullable int:
int? Bar()
In your example I would return null from your function in C#:
public string myFunc(){
//Do Stuff
if(/*whatever*/) return "abcdefg";
return null;
}
And then in your calling code:
string myVar = myFunc();
if(null != myVar)
{
throw new Exception();
}
Console.WriteLine(myVar);
It should be noted though that any time you throw exceptions for non-exceptional circumstances (meaning, if your call to myFunc could, in reasonable usage, return null) you will take a serious performance hit. It takes a long time to generate an exception, so it's generally better to avoid them, perhaps by using a pre-requisite check before even calling myFunc.
In circumstances where you're dealing with non-nullable value types, C# has a concept called Nullable Types.
If your Intention is how to return types you can use Tuple<>
public Tuple<string,bool> myFunc()
{
//Do Stuff
if(/*whatever*/) return (string) new Tuple<string,bool>("abcdefg",true);
return new Tuple<string,bool>(null,false);
}
Use Exception based programming:
public string Blah()
{
if (whatever)
{
return "abcdefg";
}
throw new Exception("Something went wrong");
}
Or you could return null or string.Empty
Personally, I prefer use null.
public string foo()
{
if (whatever)
{
return "abc";
}
return null;
}
and Then:
if(foo() != null)
{
//do something
}
else
{
// *It Didn't Work*
}

Categories

Resources