ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


Conversational C# for Java Programmers

by Raffi Krikorian
05/31/2001

Microsoft introduced C# during June of 2000 as a "modern, object-oriented programming language built from the ground up to exploit the power of XML-based Web services on the .NET platform."

Its chief architect for C#, Anders Hejlsberg, has apparently had the main goal of designing a language that is both object- and component-oriented (software written in C# is meant to be used by other software) and has looked at other languages for guidance on how to do this. Luckily for Java programmers, two of the languages studied were C++ and Java -- so any Java programmer will immediately feel familiar reading and writing C# code as the fundamental concepts and syntaxes are very similar.

The two of them side by side

The best way for a Java programmer to get his crash course in C# is probably to translate a toy Java project into that language. Let's do just that -- starting with Hello.java.

package com.oreilly.hello;
import java.io.*;
/**
 * a simple application that we are going to port
 * to c# as a demonstration
 *
 * @author Raffi Krikorian <r@bitwaste.com>
 */
public class Hello extends Object {
  /**
   * the entry point into this class -- this
   * class will ask the user for his name, then
   * reply to it
   *
   * @param args the command line arguments
   */
  public static void main( String[] args ) {

    // the name we are going to say hello to
    String name = null;

    // if the name is not on the command line,
    // then we ask to read it off standard in
    if( args.length == 0 ) {
      try {
        System.out.print( "Name? " );

        // read from standard in
        BufferedReader reader = new BufferedReader( 
            new InputStreamReader( System.in ) );
        name = reader.readLine();
      } catch( IOException error ) {
        System.err.println( "Problem with input stream" );
        error.printStackTrace();
        System.exit( 1 );
      }
    else {
      // take the name off the command line
      StringBuffer buffer = new StringBuffer();
      for( int count=0;
           count<args.length;
           count++ ) {
        buffer.append( args[count] );
        buffer.append( ' ' );
      }
      buffer.setLength( buffer.length() - 1 );
      name = buffer.toString();
    }

    // echo the name to the screen
    System.out.print( "Hello " + name + "," );
    System.out.println( " welcome to Java" );
  }
}

Comment on this articleIs C# really Java.NET? If so, what are your thoughts regarding the importance of understanding this from the perspective of a .NET developer as well as even a Java developer new to C#?
Post your comments

This is a modified version of the second Java program I wrote when I was first learning Java (the first being the requisite "Hello World"). It's a pretty trivial program, as all it does is say "Hello <name>, welcome to Java," where it gets the name either off the command line of the program or by asking the user for his name when it is first run.

Now let's do the same thing in C# in a file named Hello.cs (this code has been written and compiled with the Microsoft.NET SDK Beta 1).

using System;
using System.IO;
using System.Text;

namespace com.oreilly.hello {
  /// <summary>
  /// a simple application that was ported from 
  /// java to c#
  /// </summary>
  public class Hello : Object {

    /// <summary>
    /// the entry point into this class -- 
    /// this class will ask the
    /// user for his name, then reply to it
    /// </summary>
    /// <param name="args">the command line 
    /// arguments</param>
    /// <returns>
    /// 0 if everything goes well, 1 if 
    /// there is an error
    /// </returns>
    static int Main( string[] args ) {
      // name we are going to say hello to
      string name;

      // if the name is not on the command 
      // line, then we ask to read it off 
      // standard in
      if( args.Length == 0 ) {

        try {

          Console.Write( "Name? " );
          // read from standard in
          name = Console.ReadLine();
  
        } catch( IOException error ) {

          Console.Error.WriteLine( "Problem with input stream" );
          Console.Error.WriteLine( error.StackTrace );
          return 1;
        }
      } else {

        // take the name off the command 
        // line
        StringBuilder buffer = 
            new StringBuilder();
        foreach( string arg in args ) {
            buffer.Append( arg );
            buffer.Append( ' ' );
        }

        buffer.Length = buffer.Length - 1;
        name = buffer.ToString();
      }
  
      // echo the name to the screen
      Console.Write( "Hello " + name + "," );
      Console.WriteLine( " welcome to C#" );
      return 0;
    }
  }
}

Looks remarkably similar, no?

Comparative anatomy

Source Files

Let's dissect this program, starting with the files that the source code goes into. In Java, each class needs to exist in a like-named file (usually with the like-named extension .java) -- there are, of course, exceptions with class visible and inner classes, as those are defined within another class's .java file. C# does not have this, or any, restriction when it comes to defining classes, even when they are in different namespaces -- any part of a C# program may exist in the same .cs file, so as to form a self-contained unit.

Naming Convention

Java programs almost always follow one standard convention for naming: mixed-caps, called camel cased. (Conventions are not imposed by the compiler, but simply appear in the Java Language Specification and provide a style that programmers use and become familiar with within certain languages -- as always, there are author-personal exceptions to these rules.) Mixed-caps style doesn't use spaces or underscores between logical splits in a name, but instead uses capital letters. Object names typically have their first letter capitalized and then follow wimpy caps for the rest of the name, for example ThisIsAnObjectName. The first letter of a method, or variable, is usually in lowercase, followed by the capitalization of all other logical splits (thisIsAMethodName and thisIsAVariableName). Often, named constants (static final variables) break from this convention and are usually declared in Java by having names in all capital letters such as THISISACONSTANT.

C# follows this mixed-caps style, except that method names typically also capitalize their first letter. This is often referred to as Pascal cased. It is the standard to have the .NET Framework use Pascal case for object, method and property names, but use camel casing for parameters.

Packages/Namespaces

Java packages place classes into different author-defined namespaces for organization and readability; the rule of thumb is that related classes go into the same package (and subpackages contain closely related classes within a package, etc.). Coders can know to look in a specific package to find classes that can provide related functionality. In Java, to use classes within a package, either the "fully qualified name" (i.e. java.io.BufferedReader) can be specified within the code, or the entire package or specific class can be imported into the namespace using the "import" statement at the top of the class's source. All of the standard classes provided by the JRE are partitioned out into the java package.

C# has a similar name-partitioning scheme. To delimit different namespaces, a namespace block is specified. In the Hello.cs file, the namespace com.oreilly.hello block defines that all code within the braces are to be assigned to the com.oreilly.hello "package." What is not illustrated in the above example is that these namespaces may be nested. For example, the above namespace may have been defined as

namespace com {
  namespace oreilly {
    namespace hello {
    }
  }
}

This allows different structures to be placed within different namespaces while within the same source file. C#'s "using" statement brings an entire specified namespace into the program's space; it does not have the exact same functionality as Java's "import" statement, as it cannot bring a specific object into the program's namespace.

Constructing an Object

All classes in C# descend from the System.Object class, just as all classes in Java descend from the java.lang.Object class. And just as in Java, if a class is simply extending Object (the default), then it is not necessary to specify it in the source code. When extending a class, the use of ":" is required (in the place of the "extends" keyword in Java). In the above example, the C# Hello class's fully qualified name is com.oreilly.hello.Hello, as it is defined in that namespace. What is not shown above is how to implement interfaces -- Java provides a very clean way of differentiating when the code is extending another object (via the "extends" keyword), and when the code is implementing an interface (via the "implements" keyword). Java programmers may get annoyed with C# as it muddles the two together: interfaces may also be placed after the colon, and the compiler will only demand that the class it extends (if the class directly extends another) is the first listed after the colon.

class ClassName : ExtendedClass, Interface1, Interface2, ...

The default access modifier for classes in C# is to make them "internal," meaning they are not accessible from any other object outside the .cs file in which they are defined. The more familiar "public," "private," and "protected" modifiers are provided along with a fifth "protected internal" modifier which is the union of "protected" and "internal" properties (the modified can be accessed from a class which extends the enclosing class, or from within the file in which it has been defined). In the Hello example above, both the Java and the C# class are defined to be "public," although they do not need to be. Neither class provides functionality that any other object may wish to use -- they simply provide the proper signature so that the run-time environment may execute them.

[Ed. Note: This paragraph is no longer completely true as of current versions of C#. While the default access modifier for C# class statements is "internal". Internal means it is only visible within the assembly in which it is defined, not just within the .cs file as the author previously stated. The default access modifier for members of the class is private (not internal).]

Providing Entry and Exit Points

In order for the runtime environment to load and start a class, it needs to know where to begin. The Java language has the programmer define a public static void main( String[] args ) method so that the JVM may be able to pass the command line arguments into that method and start the program. In order to be more flexible (and more C-like), C# allows the programmer three different method signatures for the entry point. The simplest one is the public static void Main() method, followed by the public static void Main( string[] args ) and the public static int Main( string[] args )" methods. The last two signatures have the ability to take in the command line parameters passed into the program, and the third has the ability of returning an exit code.

But just like Java, having an entry point that does not have a return value does not mean that the exit code of the program cannot be set. In Java, the programmer can call System.exit( int code ) with the value to exit with. A C# programmer can set the ExitCode property in the System.Environment class and when System.WinForms.Application.Exit() is called, the value of ExitCode is returned to the run time environment.

Standard out, error, and in

The System.out, System.err, and System.in variables should be familiar to almost any Java programmer, with the first two variables being java.io.PrintStreams while the last is a java.io.InputStream; these variables allow access to the streams that they are named for. Any program can access these streams as if they were any other stream and manipulate them by sending data to and from them. To write something to standard out, the program typically calls println on the System.out variable. Reading from standard in can either be performed by using the read method or, as in Hello.java, by wrapping the InputStream in a java.io.BufferedReader and using it to read a whole line.

Support for this in C# is exactly the same: there are three variables in the System.Console class named Out, Error, and In. Out and Error are both System.IO.TextWriters, meaning that methods named Write and WriteLine can be used to send data to them. In, on the other hand, is a System.IO.TextReader. The ReadLine method can be used on In to read a line of text. C# also provides shortcut methods in System.Console named Write, WriteLine, Read, and ReadLine that will write and read from Out and In respectively -- these are the methods used in the example above. There are no shortcuts for writing to standard err.

Exceptions

In following the Hello example, you may think that there are almost no differences between Java and C# exceptions. Appearances can be deceiving. A fundamental difference is that all exceptions in C# are run-time exceptions; there is no concept of a compile-time exception in C#.

There will be a divide amongst programmers surrounding this choice. Many programmers will recognize this as an attempt to provide a faster prototyping environment; however, an equal number will notice that this will require programmers to be very careful when writing robust applications. The C# compiler does not inform the programmer when he is not taking into account an exceptional condition. What also may annoy certain programmers (the type that wishes to have as many problems as possible brought up at compile time) is that the thrown exceptions do not have to be listed in their method signature. This may make it more difficult to make sure that all possible conditions are being dealt with.

Source Documentation

Java programmers may embed JavaDoc comments; C# programmers may embed XML. The "javadoc" tool in the J2SE provides a way to use different doclets to guide the output of the generated documentation. By default, "javadoc" generates the familiar framed HTML. C# can use the compiler to generate a well-formed XML file containing the documentation from the source code that looks like
<?xml version="1.0"?>
<doc>
    <assembly>

<name>Hello</name>
    </assembly>
    <members>
        <member 
name="T:com.oreilly.hello.Hello">

<summary>
   a simple application that was ported from java to c#
</summary>
        </member>
        <member 
name="M:com.oreilly.hello.Hello.Main(System.String[])">

<summary>
  the entry point into this class -- this class will
  ask the user for his name, then reply to it
</summary>

<param name="args">the command line arguments</param>
            
<returns>
 0 if everything goes well, 1 if there is an error
</returns>
        </member>
    </members>
</doc>

The common next step would be to run this XML through an XSLT transformation to generate HTML or whatever other documentation may turn out to be helpful.

Compilation and Running

Hello.cs can be compiled using the csc.exe Running

csc Hello.cs

which generates a 3584 byte Hello.exe file in the current working directory. Hello.exe is a standalone program only relying on certain DLLs to be present from the Microsoft.NET SDK -- it can be run from the command line by simply typing "Hello" on the command prompt.

Compared to the 1284 byte Hello.class file outputed by Sun Microsystem's JDK 1.3 for Windows, the Hello.exe may seem bloated until you remember that the Java program must be run within a 20 MB Java virtual machine.

Conclusion

If you are a Java programmer, there is no reason why, after some basic reading, you should not be able to decipher any simple C# program as C# -- the concepts are the same, and most of the syntax is the same (with a few alterations and a few other additions). If you have a desire or need to program within the Common Language Runtime, or within .NET, read the rest of this series -- it should be pretty easy to figure out. This article is the introduction to a series of articles entitled "Conversational C# for Java Programmers."  Each article will focus on different aspects of the language: the first covers objects, methods, syntax, and other concepts not necessarily familiar to the Java programmer.  The second will cover IO and networking, the third, multithreading, and the last, GUI applications.

Raffi Krikorian makes a career of hacking everything and anything. Professionally, he is the founding partner at Synthesis Studios: a technological design and consulting firm that orchestrates his disjointed train of thought.


Return to the .NET DevCenter.

Copyright © 2009 O'Reilly Media, Inc.