WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Contrasting C# and Java Syntax
Pages: 1, 2, 3

Properties

Properties are a C# construct that formalizes the getter/setter pattern seen in many Java classes. The Java paradigm of having a get method that takes one parameter and a set method that returns the said parameter is compacted. So the following Java code:



private int property;
public int getProperty() {
  return this.property;

}

public void setProperty( int property ) {
  this.property = property;

}

can be written in C# as

private int property;
public int Property {
  get {
    return this.property;

  }

  set {
    // value is an implicit variable generated by the
    //  compiler to represent the parameter
    this.property = value;

  }

}

which can be easily used from inside of a C# program with just

int currentValue = Property;
Property = newValue;

Behind the scenes, C# has actually compiled the property to two methods in the .NET intermediate language framework named get_Property and set_Property. These methods cannot be called directly from C#, but other languages using the MSIL should be able to access these getters/setters.

Accessibility Modifiers

Access modifiers do just what their names imply -- they restrict the ability for only certain code to change a field. The ones that we are used to are private, protected, default, and public. C#, in turn, has five modifiers

  • public - means the same thing that it means in Java. As long as you can get to the enclosing object, any thing has free access to this member.
  • protected - yet again, the same thing as Java. Free reign over the member from classes that extend the containing classes.
  • internal - this is a new one to Java programmers, as this means that a member is accessible from the entire assembly. All the objects you define inside a .cs file (you can define more than one object inside the .cs file, unlike Java, where you can usually define only one object) have a handle to the internal member.
  • protected internal - think of this one as the union of protected and internal, as the item is is modifying is either protected or internal. This item can be accessed from the entire assembly, or within objects which derive from this class.
  • private - just as in Java. Nothing except the enclosing class may access this.

These modifiers can be applied to the same structures that Java allows you to use them with: you can modify the accessibility to objects, methods, and variables. We are mentioning these here, so we can talk about objects and inheritance next.

Objects, Classes, and Structs

All Java programmers have to already be familiar with the concepts of classes, objects, and inheritance, so learning the C# equivalent is just a manner of showing the syntactical differences. Defining a class is trivial:

class A {

}

will do it for you. And extending another uses the : instead of the extends keyword so

class B : A {

}

means that B extends A.

Interfaces can be implemented in the same (albeit slightly confusing to the Java programmer) manner with interface C being implemented by class D with

class D : C { 

}

and D can both extend B and implement C in

class D : B, C {

}

Note that B has to be placed before C in the list, and any other interfaces to implement are added to the comma-separated list.

All classes are passed by reference to method calls. This means that the variable being defined and passed around is actually a reference to another memory space containing the actual object. Everything in Java, except the primitives, is passed by reference -- there is no way to define anything that can be passed by value. To define an object that is passed by value in C#, a syntactical construct named a "struct" can be used.

struct E {

}

The struct looks and acts exactly as a class (they even all derive from System.Object), except with the following restrictions:

  • structs are passed by value instead of by reference
  • structs cannot extend anything (nor can anything extend them) -- they may, however, implement interfaces
  • structs may not define a constructor with no parameters
  • structs that define constructors with parameters must explicitly define all fields before they return control to the caller

Using a struct for a custom type does have an advantage in that it can be very efficient to allocate. When allocating arrays of classes, you first have to define an array of references. Then the program needs to iterate through this array to instantiate each class one by one. Merely allocating an array of structs will allocate each individual struct in a contiguous block. As mentioned above, each simple type in C# is defined as a struct which provides it the standard pass-by-value semantics that Java programmers are used to.

Self Referentiation

Self referentiation is possible within C# objects just as they are within Java objects. this means semantically the same thing, but C# uses the keyword base instead of super. Both this and base can be used in methods and constructors just as this and super can be used in Java.

Overriding Methods

All methods in a object are "final" (in the Java sense of the word) by default. In order for a method to be overridden by an inheriting object, the original method needs to be marked "virtual" and all methods overriding the virtual method in the inherited classes must be marked "override." For example:

public class A : Object {
  public virtual void toOverride() { }

}

public class B : A {
  public override void toOverride() { }

}

is required in C# for the compiler not to complain when defining the inheriting class.

Type Conversion

Java programmers are usually only familiar with type conversion between primitive types, and when upcasting or downcasting an object to its superclass or subclass. C# allows for the ability to define custom type conversions between any two objects. Two types of transformations should be kept in mind:

  • explicit conversion - this type of conversion requires that the destination type must be specified in the statement, as the conversion is not guaranteed to work, or if it does, it may result in a loss of information. Java programmers are familiar with explicit conversion when casting an object to one of its subclasses; the subclass must be listed in parentheses.
  • implicit conversion - these conversions do not require the parenthetical type, as this type of conversion is guaranteed to work.

In the following example, we provide the ability to convert a double to a FlooredDouble, and vice versa. We need to define an explicit conversion for double to FloorDouble, as information may be lost in the conversion. For the other way around, an implicit conversion may be defined, as no information is going to be lost.

public class FloorDouble : Object {
  private double value;

  public FloorDouble( double value ) {
    this.value = Math.Floor( value );

  }

  public double Value {
    get {
      return this.value;

    }

  }

  public static explicit operator FloorDouble( double value ) {
    return new FloorDouble( value );

  }

  public static implicit operator double( FloorDouble value ) {
    return value.Value;

  }

}

// this class can be used by
FloorDouble fl = (FloorDouble)10.5
double d = fl;

Operator Overloading

Wouldn't it be nice if Java programs could take two java.lang.Double objects and just use + to add them together and get another Double object back? Operator overloading in C# is simple. The FloorDouble class defined above can be extended to contain the static method

public static FloorDouble operator + ( FloorDouble fd1, FloorDouble fd2 ) {
  return new FloorDouble( fd1.Value + fd2.Value );

}

and then statements such as

FloorDouble fd1 = new FloorDouble( 3.5 );
FloorDouble fd2 = new FloorDouble( 4 );
FloorDouble sum = fd1 + fd2;

become legal.

Organizing Source Code

C# does not place any requirement on file organization -- a programmer could clump the entire C# program into one .cs file. (Java, on the other hand, usually requires one .java file per Java class.)

The C# language does, however, provide a way to conceptually separate out the program's objects in a manner similar to Java's packages. Using namespaces, related types can be grouped into a hierarchy. With no "namespace" block, the program exists in a default namespace. To define one, use

namespace com.oreilly {

}

and all types defined in the block exist in the com.oreilly hierarchy. These hierarchies can also be nested with

namespace com {
  namespace oreilly {

  }

}

allowing code to be written in both enclosing namespaces.

To import a namespace, the "using" keyword is needed. This functions basically like the "import" statement in Java, but lacks the ability to import a specific class; only entire namespaces can be imported. using can also be used to alias types and namespaces and save you valuable keystrokes. For example a class defined like

namespace a.really.long.namespace {
  class theClass {

  }

}

can be aliased to something a lot shorter with using, as in

using short = a.really.long.namespace.theClass;

Conclusion

Related articles:

Conversational C# for Java Programmers

Comparing C# and Java

Note that this article is nowhere near complete in covering all the syntaxes in C#; we did not cover enums, delegates, unsafe code, the preprocessor, and many other statement types. We instead covered a list of statements which should be familiar and pertinent to those familiar with Java. And knowing what you already know about Java programming, you should be able to use the statements listed above and my previous article to get you on your feet and to create a full-fledged C# program.

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.