I am a C# beginner. I found there are 2 way to write codes and output the same results. Could you explain the different between them? And when to use #1 and #2?
#1
class Program
{
static void Main()
{
Program min = new Program();
Console.WriteLine(min.isMin(1, 2));
Console.ReadLine();
}
int isMin(int value1, int value2)
{
int Min;
return Min = Math.Min(value1, value2);
}
}
#2
class Program2
{
static void Main()
{
Console.WriteLine(isMin(1, 2));
Console.ReadLine();
}
static int isMin(int value1, int value2)
{
int Min;
return Min = Math.Min(value1, value2);
}
}
The difference between #1 and #2 is that in #1, isMin is an instance member function of the class Program, therefore you have to create an instance of the Program class
Program min = new Program()
and only then call the instance member function isMin:
min.isMin(..)
In #2, isMin is a static member function of the Program class, and since Main is also a static member function of the same class, you can make a direct call to isMin from the Main function.
Both are valid. The static function Main is the "entry point" into the program which means it gets executed first. The rest is just Object-Oriented semantics.
EDIT
It seems that in order to better illustrate the point an example would be in order.
The two programs below are pretty useless outside of their intended purpose of showing the differences between encapsulating your program logic into objects, and the alternative -using static functions.
The program defines two operation and will work on two numbers (10 and 25 in the example). As the program runs, it will trace its' operations to a log file (one for each number). It is useful to imagine that the two operations could be replaced by more serious algorithms and that the two numbers could be replaced by a series of more useful input data.
//The instance-based version:
class Program
{
private System.IO.StreamWriter _logStream;
private int _originalNumber;
private int _currentNumber;
public Program(int number, string logFilePath)
{
_originalNumber = number;
_currentNumber = number;
try
{
_logStream = new System.IO.StreamWriter(logFilePath, true);
_logStream.WriteLine("Starting Program for {0}", _originalNumber);
}
catch
{
_logStream = null;
}
}
public void Add(int operand)
{
if (_logStream != null)
_logStream.WriteLine("For {0}: Adding {1} to {2}", _originalNumber, operand, _currentNumber);
_currentNumber += operand;
}
public void Subtract(int operand)
{
if (_logStream != null)
_logStream.WriteLine("For {0}: Subtracting {1} from {2}", _originalNumber, operand, _currentNumber);
_currentNumber -= operand;
}
public void Finish()
{
Console.WriteLine("Program finished. {0} --> {1}", _originalNumber, _currentNumber);
if (_logStream != null)
{
_logStream.WriteLine("Program finished. {0} --> {1}", _originalNumber, _currentNumber);
_logStream.Close();
_logStream = null;
}
}
static void Main(string[] args)
{
Program p = new Program(10, "log-for-10.txt");
Program q = new Program(25, "log-for-25.txt");
p.Add(3); // p._currentNumber = p._currentNumber + 3;
p.Subtract(7); // p._currentNumber = p._currentNumber - 7;
q.Add(15); // q._currentNumber = q._currentNumber + 15;
q.Subtract(20); // q._currentNumber = q._currentNumber - 20;
q.Subtract(3); // q._currentNumber = q._currentNumber - 3;
p.Finish(); // display original number and final result for p
q.Finish(); // display original number and final result for q
}
}
Following is the static functions based implementation of the same program. Notice how we have to "carry our state" into and out of each operation, and how the Main function needs to "remember" which data goes with which function call.
class Program
{
private static int Add(int number, int operand, int originalNumber, System.IO.StreamWriter logFile)
{
if (logFile != null)
logFile.WriteLine("For {0}: Adding {1} to {2}", originalNumber, operand, number);
return (number + operand);
}
private static int Subtract(int number, int operand, int originalNumber, System.IO.StreamWriter logFile)
{
if (logFile != null)
logFile.WriteLine("For {0}: Subtracting {1} from {2}", originalNumber, operand, number);
return (number - operand);
}
private static void Finish(int number, int originalNumber, System.IO.StreamWriter logFile)
{
Console.WriteLine("Program finished. {0} --> {1}", originalNumber, number);
if (logFile != null)
{
logFile.WriteLine("Program finished. {0} --> {1}", originalNumber, number);
logFile.Close();
logFile = null;
}
}
static void Main(string[] args)
{
int pNumber = 10;
int pCurrentNumber = 10;
System.IO.StreamWriter pLogFile;
int qNumber = 25;
int qCurrentNumber = 25;
System.IO.StreamWriter qLogFile;
pLogFile = new System.IO.StreamWriter("log-for-10.txt", true);
pLogFile.WriteLine("Starting Program for {0}", pNumber);
qLogFile = new System.IO.StreamWriter("log-for-25.txt", true);
qLogFile.WriteLine("Starting Program for {0}", qNumber);
pCurrentNumber = Program.Add(pCurrentNumber, 3, pNumber, pLogFile);
pCurrentNumber = Program.Subtract(pCurrentNumber, 7, pNumber, pLogFile);
qCurrentNumber = Program.Add(qCurrentNumber, 15, qNumber, qLogFile);
qCurrentNumber = Program.Subtract(qCurrentNumber, 20, qNumber, qLogFile);
qCurrentNumber = Program.Subtract(qCurrentNumber, 3, qNumber, qLogFile);
Program.Finish(pCurrentNumber, pNumber, pLogFile);
Program.Finish(qCurrentNumber, qNumber, qLogFile);
}
}
Another point to note is that although the first instance-based example works, it is more common in practice to encapsulate your logic in a different class which can be used in the Main entry point of your program. This approach is more flexible because it makes it very easy to take your program logic and move it to a different file, or even to a different assembly that could even be used by multiple applications. This is one way to do that.
// Another instance-based approach
class ProgramLogic
{
private System.IO.StreamWriter _logStream;
private int _originalNumber;
private int _currentNumber;
public ProgramLogic(int number, string logFilePath)
{
_originalNumber = number;
_currentNumber = number;
try
{
_logStream = new System.IO.StreamWriter(logFilePath, true);
_logStream.WriteLine("Starting Program for {0}", _originalNumber);
}
catch
{
_logStream = null;
}
}
public void Add(int operand)
{
if (_logStream != null)
_logStream.WriteLine("For {0}: Adding {1} to {2}", _originalNumber, operand, _currentNumber);
_currentNumber += operand;
}
public void Subtract(int operand)
{
if (_logStream != null)
_logStream.WriteLine("For {0}: Subtracting {1} from {2}", _originalNumber, operand, _currentNumber);
_currentNumber -= operand;
}
public void Finish()
{
Console.WriteLine("Program finished. {0} --> {1}", _originalNumber, _currentNumber);
if (_logStream != null)
{
_logStream.WriteLine("Program finished. {0} --> {1}", _originalNumber, _currentNumber);
_logStream.Close();
_logStream = null;
}
}
}
class Program
{
static void Main(string[] args)
{
ProgramLogic p = new ProgramLogic(10, "log-for-10.txt");
ProgramLogic q = new ProgramLogic(25, "log-for-25.txt");
p.Add(3); // p._number = p._number + 3;
p.Subtract(7); // p._number = p._number - 7;
q.Add(15); // q._number = q._number + 15;
q.Subtract(20); // q._number = q._number - 20;
q.Subtract(3); // q._number = q._number - 3;
p.Finish();
q.Finish();
}
}
The key difference here is based on object oriented programming. C# is an object oriented language, and most of the things in it are objects. In this case Program is an object. It is special because it has the static void Main() function, that is the 'entry point' for the program.
The difference comes because of the static modifier on the isMin function. Classes define how the objects work. When you actually make one, as you do with new Program() you have 'instantiated', or made an actual working copy of that object.
Usually this is done to track a set of variables that are part of that object, but in this case there are no such variables.
In the first case, you are making an instance of the object program, and telling it to execute its "isMin" function on that instance. In the second case, you are not making any instances, and you are telling it to execute the "isMin" function that is associated with the class (not the instance of the object). There is no real difference here except some easier syntax, because there is no data being tracked in an object.
You will find that it matter when you have data on the objects, because you will not be able to access 'instance' data when you are in a static function. To understand more, look into object oriented programming.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With