patterncsharpModerate
Am I coding Java in C#?
Viewed 0 times
codingjavastackoverflow
Problem
Note: This ended up being much longer than I was expecting. I have a number of side questions that relate to specific parts of the code for if you don't want to slog through all this mess.
Background
I have had some experience in Java, but recently decided to learn C#. I would like to know if my first program is idiomatic.
I got the idea for this program out of a Java textbook I had lying around. Here's what it says:
Write a program that evaluates expressions typed in by the user. The
expressions can use real numbers, variables, arithmetic operators,
parentheses, and standard functions (sin, cos, tan, abs, sqrt, and log.)
A line of input must contain exactly one such expression. If extra
data is found on a line after an expression has been read, it is
considered an error. A variable name must consist of letters. Names
are case-sensitive. The program should accept commands of two types
from the user. For a command of the form
expression is evaluated and the value is output. For a command of the
form
the value is assigned to the variable. If a variable is used in an
expression before it has been assigned a value, an error occurs.
I learned about using text mode in C#, so I went a little crazy with it.
Structure
My program is probably over 1000 lines long, so I'm not going to post the whole thing. Here's the basic breakdown of all the classes:
Background
I have had some experience in Java, but recently decided to learn C#. I would like to know if my first program is idiomatic.
I got the idea for this program out of a Java textbook I had lying around. Here's what it says:
Write a program that evaluates expressions typed in by the user. The
expressions can use real numbers, variables, arithmetic operators,
parentheses, and standard functions (sin, cos, tan, abs, sqrt, and log.)
A line of input must contain exactly one such expression. If extra
data is found on a line after an expression has been read, it is
considered an error. A variable name must consist of letters. Names
are case-sensitive. The program should accept commands of two types
from the user. For a command of the form
print , theexpression is evaluated and the value is output. For a command of the
form
let = , the expression is evaluated andthe value is assigned to the variable. If a variable is used in an
expression before it has been assigned a value, an error occurs.
I learned about using text mode in C#, so I went a little crazy with it.
Structure
My program is probably over 1000 lines long, so I'm not going to post the whole thing. Here's the basic breakdown of all the classes:
- BraceMatcher.cs Contains a class that validates that the braces in an expression match.
- CommandHandler.cs Contains a class that handles the commands sent from the user. A private nested inner exception class called MalformedAssignmentException deals with variable assignment commands that are malformed.
- ConsoleFormatter.cs Contains a class that formats the Console IO for text mode.
- IExpression.cs Contains an interface that represents a mathematical expression. The only method it defines is
double Evaluate().
- TermExpression.cs
Solution
First off, for somebody who is just learning C# you use it better than some of the people I work with.
Now to answer your questions:
-
You are correct, there is no native way to read numbers from the
The code would look something like this:
-
There is nothing wrong with default parameters. I like them better than having multiple constructors. I too think it's much cleaner.
-
There is nothing wrong with an
-
Using delegates this way is perfectly acceptable. I would look into
-
Your exception handling could be improved. You can catch multiple exceptions from one call:
Now to answer your questions:
-
You are correct, there is no native way to read numbers from the
Console in C#. You could look at decimal.TryParse which tries parsing the input.The code would look something like this:
var input = Console.ReadLine();
var inputAsNumber = 0d;
if (!decimal.TryParse(input, out inputAsNumber)
{
// throw favorite exception
}-
There is nothing wrong with default parameters. I like them better than having multiple constructors. I too think it's much cleaner.
-
There is nothing wrong with an
IsEmpty method. C# has one for strings string.IsNullOrEmpty(string)-
Using delegates this way is perfectly acceptable. I would look into
Action and Action though. I think they are a little more common.-
Your exception handling could be improved. You can catch multiple exceptions from one call:
try
{
numBadCommands = 0;
var name = ReadVariableName();
ReadAssignmentOperator();
var value = expressionReader.Read().Evaluate();
expressionReader.StoreVariable(name, value);
formatter.WriteOutput(
String.Format("{0} set to {1}", name, value));
}
catch (MalformedAssignmentException ex)
{
throw;
}
catch (InvalidExpressionException ex)
{
throw;
}
catch (Exception ex)
{
if (Console.In.Peek() != -1)
{
Console.ReadLine();
}
formatter.WriteOutput(ex.Message);
}Code Snippets
var input = Console.ReadLine();
var inputAsNumber = 0d;
if (!decimal.TryParse(input, out inputAsNumber)
{
// throw favorite exception
}try
{
numBadCommands = 0;
var name = ReadVariableName();
ReadAssignmentOperator();
var value = expressionReader.Read().Evaluate();
expressionReader.StoreVariable(name, value);
formatter.WriteOutput(
String.Format("{0} set to {1}", name, value));
}
catch (MalformedAssignmentException ex)
{
throw;
}
catch (InvalidExpressionException ex)
{
throw;
}
catch (Exception ex)
{
if (Console.In.Peek() != -1)
{
Console.ReadLine();
}
formatter.WriteOutput(ex.Message);
}Context
StackExchange Code Review Q#23900, answer score: 13
Revisions (0)
No revisions yet.