There are articles all over the internet comparing C# and Java so why am I writing one? I started programming in
Java in 1996 after several years of developing applications in C++. Since April of 2002, I have been writing programs
in C#. That means over the last 10 years I have developed real life production applications in C++, Java, and C#.
I also don't have any ax to grind. I think I can be fair in an evaluation of C#, something that seems to be missing
in many of the evaluations I have read.
The question of why C# was invented has more to do with the politics between Sun and Microsoft than anything else.
Once Microsoft was excluded from the Java world, the development of C# was virtually assured. Microsoft needed
a new language to go with their .Net environment and C++ and VB were simply too complicated or too limited for
this new environment.
So is C#, Microsoft's brand of Java? To put it simply, yes. C# is a lot like Java and a Java developer will find
the transition between the two languages to be very simple. You will find that many things in the language are
identical, some other things are very similar, while a few others are very different. Rather than do a complete
comparison of the two languages, I would like to discuss those things that Java programmers (in my opinion) will
either wish Java had or will hate.
This was in C++ and I hated it in that language. For those who are unfamiliar with the idea behind operator overloading,
I will give you an example out of Java. The String class has the plus sign overloaded so that you can concatenate
two Strings. This is a convenience so that we can code s1 = s2 + s3 instead of s1 = s2.concat(s3). However, when
operator overloading is unlimited, we end up with odd constructs. In C#, you can overload any operator including
==, !=, < , and >. So instead of using an equals method to compare two objects, you can overload the equals
operator to compare any two objects. This might sound nice, but can easily cause confusion. Is obj1 == obj2 a reference
compare or an object contents compare? There's no way to know unless you look at the API. Of course, we have the
same problem with the equals method in Java since it may or may not be overridden but at least we always know that
== is a reference compare. In C#, if == is overloaded, there is no way to do a reference compare! You might think
that this isn't too bad but what about other operators? What does it mean if I do employee1 = employee2 + employee3?
Although there may be times when it is useful (date1 = date2 - date3) , it tends to create more confusion than
it is worth.
One capability with operator overloading that is very nice is the ability to create castings between classes. C#
allows you to create explicit or implicit casts between classes that would not normally be permitted. For example,
let's say that we have an Employee class that is the parent of ExemptEmployee and NonExemptEmployee. In Java there
is no way to cast a NonExemptEmployee to be an ExemptEmployee. C# allows you to set up a method to do just that.
The method will take in a NonExemptEmployee and return an ExemptEmployee. The method gets executed automatically
when casting is needed (implicit) or when a cast is made (explicit). This can be very useful if you have a method
that takes in ExemptEmployee objects but all you have is a NonExemptEmployee object.
We all know by now that properties should be kept private and then accessed through public get and set methods.
The makers of C# agree with this concept but rather than use Java-like public get and set methods, they designed
a way to make it look like you are accessing public properties even though you are really running get and set methods.
In this way you can code office1.DeptNum = 101 and actually be running a set method. The code looks like this:
public int DeptNum { get { return deptNum; } set { deptNum = value; } } |
Just as in Java, C# uses pass by value. But C# also allow the programmer to pass by reference. Although parameters
passed by reference must be clearly identified, the whole concept of pass by reference seems very anti-OO to me
because you are accepting side effects as being desirable. Methods should return values, not replace values passed
to them. This isn't a terrible thing, but I could have easily lived without it.
C# does not require you to catch exceptions. I don't understand why this is the case because forcing exceptions
to be caught makes for cleaner, more reliable code. In Java, if you fail to catch an exception, you get a nice
compile error that let's you know what exceptions a method can throw. This makes it easy to write reliable code
without having to check the API every time you make a method call. C# does not give any warnings when you fail
to code a catch around a method call. This forces you to check the API to figure out what exceptions might be thrown.
A definite pain in the neck. The end result is that try...catch isn't used nearly as often as it should be in C#.
C# uses the C++ model for polymorphism which means you must take positive action to make a method eligible to take
part in polymorphism. What does this mean exactly? In Java, you can override a method in your parent class and
as long as the parent method isn't final there isn't a problem. You get runtime method binding which is very powerful.
C# prefers to use compile-time binding unless you specifically tell it otherwise. C# adds three keywords to make
this all work; virtual, override, and new. Since programmers tend to not code their classes with the next programmer's
concern in mind, it is very unlikely that the original programmer will write the necessary code to insure that
programmers extending their class will be able to override their methods. Java wins hands down in this area.
The foreach statement is one of the most convenient ways to iterate through a collection or an array. It allows
you to process an entire collection and cast the objects to the correct type in one handy little statement. Here's
an example:
public void AMethod(ArrayList list) { foreach (Employee emp in list) { Console.WriteLine(emp.Name); } } |
This is something that really belongs in Java. It helps create more reliable code by insuring type safety at compile
time. For example, if you have a field that should only contain the days of the week, to insure type safety at
compile time, you would have to create a special class to insure that only the days of the week can end up in the
field. This can only be tested at runtime. Using an Enumerator, you can test what is being moved to the field at
compile time. How do we do this?
First we create an enumerator which contains the days of the week:
enum DayOfTheWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday } |
DayOfTheWeek day; day = DayOfTheWeek.Sunday; |
You have an int and you want to stick it into a collection. Or you have a float and you want to convert it into
a string. In C# this is a breeze. Whenever you use a primitive in a place that requires an object, C# automatically
turns the primitive into an object. This is called "boxing". basically it means that you can treat all
your primitives as if they were objects without paying the overhead of having them always be objects. So you can
do something like this:
int i = 50; arrayList.Add(i); string s = i.ToString( ); |
One of the nice things about C++ is the ability to use function pointers. Delegates give you a very similar functionality.
In many ways it is similar to the event model used in Java but it has the added advantage of not tying you to a
particular method name. One of the problems with Java's event model is that if you use one class to receive event
notifications from different objects (let's say one class is handling the action event for three Buttons) then
all the notifications will go to the same method. The method has to figure out which Button caused the method to
be triggered. The delegate model allows you to have different methods for each Button object if you wish. Instead
of passing just an object to be notified, the delegate model allows you to pass a method to be called when the
event is triggered.
OKButton.Click += new System.EventHandler(buttonHandler.OKButton_Click); CancelButton.Click += new System.EventHandler(buttonHandler.CancelButton_Click); |
Notice that setting up a delegate involves using operator overloading. In this case, when the OKButtum is clicked, the OKButton_Click method of the buttonHandler object will be invoked. When the CancelButton is clicked, the CancelButton_Click method will be invoked. The actual method has to have a certain signature that is determined by the delegate model that is used. For button clicks, the method signature looks like this:
private void OKButton_Click(object sender, System.EventArgs e) { } |
Although the delegate model is used for events, it can be used for any situation where a callback is useful.
There are two nice improvements in the switch. First, you can use a string in your case. Second, there is no way
to accidentally fall through from one case to another. If you want to fall through you have to specifically tell
the compiler.
C# provides direct support for multi-dimensional arrays. It also supports the jagged arrays found in Java. You
can code this kind of construct:
string[,] cityState = new string[25,2]; |
C# has the "is" keyword which is basically the same as instanceof. You can code something like: if (a is Animal).
But C# also has the "as" keyword which is used for casting.
Look at this piece of Java code (assume that Animal is the parent class of Dog):
Dog d; Animal a = new Animal(); d = (Dog)a; // ClassCastException |
Dog d; Animal a = new Animal(); d = a as Dog; |
So which is the better language? They are both great languages and I enjoy working in both of them. Both languages
have all the features that you expect in a modern object oriented language. Knowledge of one of these is easily
transferred to the other. Thebest part is that C# has opened the Microsoft world to Java developers. By removing
the reliance on C++ and Visual Basic, .Net has created an opportunity for Java programmers to take their skills
into a job market that was previously closed to them.
By the way, some of the things I pointed out as things I like about C# are planned to be added to Java at some
point. You can take a look at the "From Mantis
to Tiger" site for a look at some of the proposed enhancements in J2SE 1.5.