C# pitfalls for Java Devs - Static Members in Template Classes [Part 2]

Introduction

Previously I discussed one of the major differences between C# and Java - method overriding. Because of it Java and C# code, which look almost identical, can have very different semantics. Similarly, C# and Java generics differ significantly in terms of the underlying semantics, which can be quite confusing for a Java programmer.

Example

Let us consider the following seemingly analogous code snippets implemented in both languages.

C# code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Animal { }
public class Lion:Animal { }
public class Bear:Animal { }
public class Cage<T>;
{
    private static int instanceCount = 0;
    public Cage()
    {
        instanceCount++;
    }
    public void PrintInstanceCount()
    {
        System.Console.WriteLine(instanceCount);
    }
}

Java code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Animal { }
public class Lion extends Animal { }
public class Bear extends Animal { }
public class Cage<T>;
{
    private static int instanceCount = 0;
    public Cage()
    {
        instanceCount++;
    }
    public void PrintInstanceCount()
    {
        System.out.println(instanceCount);
    }
}

Now let us consider the following invocations:

1
2
3
4
5
6
Cage <Animal> ca = new Cage<Animal>();
Cage <Lion> cl = new Cage<Lion>();
Cage <Bear> cb = new Cage<Bear>();
ca.PrintInstanceCount();
cl.PrintInstanceCount();
cb.PrintInstanceCount();

Many will be surprised to see that the results are different, as per the following table:

Command / Language C# Java
ca.PrintInstanceCount(); 1 3
cl.PrintInstanceCount(); 1 3
cb.PrintInstanceCount(); 1 3

Java implements type erasure, which means that type parameters are erased at compile time and at a runtime there is a single class for each template. Thus, in the previous example at runtime there is a single static member variable for all instances of Cage, independent of the type parameter.

Conversely, the C# compiler (i.e. the Just In Time compiler - JIT) ensures that all closed types (e.g. Cageand Cage) have their own static fields. Thus, to the programmer they seem as different types/classes.

Consequences

As a result C# does not let you access the static members of a template class without specifying the template parameters:

1
2
3
Cage.instanceCount = 5;         // Invalid in C#, Valid in Java
Cage<Lion>.instanceCount = 5;   // Valid in C#, Invalid in Java
Cage<Bear>.instanceCount = 5;   // Valid in C#, Invalid in Java

Also, C# does not let you have an entry point (i.e. a Main method) in a template class.

comments powered by Disqus