At first glance Generics in Java and .NET are very similar: neither of both gets anywhere close to what C++ templates can do and their inventors see the primary use in collections or holder classes (like Java's SoftReference or .NET's Nullable).

Under the covers they are very different. In Java, Generics don't really exist in your byte-code, the Java compiler knows and sees the generic types, but after that they've been "erased". In .NET on the other hand the generic type is completely known at runtime, there even are reflection methods for accessing the generic types or creating new instances of generic classes passing in a type.

As a result, the .NET implementation doesn't suffer from some of the problems erasure exhibits in Java land. Mixing of generics and varargs for example - the code below is perfectly legal:

    public class CompositeCollection<E> : ICollection<E> {
        public void AddComposited(params ICollection<E>[] colls) {

As a side note on Stephen Colebourne's later post, an array T[] not only implements IEnumerable<T> it even implements IList<T> in .NET 2.0.

Without erasure it is also possible to implement the same generic interface twice using different type parameters:

    class StringifiedInteger : IComparable<string>, IComparable<int> {

Yes, you can use value types (primitives) as type parameters as well, List<int> just works. Without boxing, that is.

This may sound as if the .NET generics were superior to Java's in each and every way, this is not completely true.

Part of the reason for erasure was that you could pass your type-safe generic collection classes to unsuspecting legacy code that wanted to work on plain old collections. Microsoft didn't even try to reach this point, instead they've added a new namespace System.Collections.Generic (and VS2005 will remind you of it by adding a using clause for it to each and every class you create - no, that doesn't annoy me, not at all, thank you) and ICollection<T> doesn't even inherit from ICollection.

One Java generics' feature I really miss in .NET and that isn't related to erasure at all is wildcard parameters. Stephen's CompositeCollection is a typical example for a method where wildcards would be useful. Given

    public class CompositeCollection<E> extends Collection<E> {
        public void addComposited(Collection<E> c) ...

    CompositeCollection<Shape> shapes = new CompositeCollection<Shape>();

I won't be able to invoke addComposited with ArrayList<Rectangle> - neither in Java nor using the C# equivalent. In Java you'd use a wildcard type parameter

        public void addComposited(Collection<? extends E>) ...

instead and it works as intended.

Using C# you have to make the method generic itself and use what Microsoft calls a naked type constraint in the docs:

        public void AddComposited<T>(ICollection<T> c) where T : E ...

and invoke it like

            CompositeCollection<Shape> shapes = new CompositeCollection<Shape>();
            shapes.AddComposited(new List<Rectangle>());

fortunately the compiler (both Microsoft's csc as well as Mono's gmcs compiler) is smart enough to infer the method's type parameter from the argument. Still I feel the "collection of unknowns" is expressed in Java in a better way.

path: /en/dotNet | #