Strongly typed properties in Java vs C#

Posted on Thu 19 January 2012 in Coding

The background for this post was that I needed to implement strongly typed properties in a C# project. With strongly typed property, I specifically mean a strongly typed version of public object GetProperty(string propertyName), where the property name is a constant (or name) of some sort, and the return type is property specific, so that no type casting is required at the call site. Furthermore, I wanted the properties to be derived from other properties on-demand, but cached for subsequent access. This turned out to be non-trivial in C#, and I’ll explain why in a moment. But first, let me show how I’ve done it in Java several times before.

The Java version

Thanks to Java’s generics, and precisely because they are implemented with type erasure, the solution is quite simple. First, we need a generic interface for property classes to implement:

public interface Property<T> {
    T get(PropertyContainer container);
}

Next, by declaring a property-getting method that takes a generic Class parameter in our property container class, we can rely on the compiler to infer the return type for us:

public class PropertyContainer {
    public T getProperty(Class<? extends Property<T>> clazz) {
        // ...
    }

If you’re unfamiliar with Java generics, the Class<? extends Property<T>> parameter type might be intimidating, but what it says is that the method accepts a Class instance whose generic type argument is any class that implements the Property interface, and since we specify T here, the compiler can just look at the type of the passed argument to determine what the return type must be. I’ve left out the getProperty implementation because it’s not very relevant for the discussion, but it comes down to a map lookup using the class as the key. Now, let’s implement the following two properties, one of which is derived from the other:

public class RootProperty implements Property<Integer> {
    public Integer get(PropertyContainer container) {
        return 42;
    }
}

public class DerivedProperty implements Property<Double> {
    public Double get(PropertyContainer container) {
        return container.getProperty(RootProperty.class) * 3.14;
    }
}

…and you can see a call site already here in the DerivedProperty property. Neat, isn’t it? We use the class of the RootProperty property as our “constant”, and no type cast is needed to be able to multiply the property value with a double value, which proves that the compiler has inferred the return type properly!

Moving on to C#, the starting point…

The C# version

Ok, so how to achieve the same thing in C#? Well, it’s a bit harder! And actually, that’s because of how C# implements generics, which ironically is considered to be an improvement compared to Java’s version since type information is retained during runtime. Let’s see how generic classes compare in the different languages:

Generic class comparison in Java vs. C#
Language Expression Result
Java ArrayList<String>.class == ArrayList<Integer>.class true
C\# typeof(List<string>) == typeof(List<int>) false

Opposites! In C#, the two types are different specializations of the generic List class. In Java, the two types resolve to the non-generic ArrayList class at runtime.

Unlike Java’s Class class, C#‘s Type class doesn’t have any generic version. I suppose one reason is that reflection would be pretty painful if it did. Thus, there is no way to pass a class to a property-getting method and have the C# compiler infer the return type. You might be tempted to do something similar to the Java version:

public class IProperty<T> {
    T Get(PropertyContainer container);
}

…and then expect to be able to declare a property-getting method that allows you to make a call like container.GetProperty(). But to do so turns out to be difficult:

public class PropertyContainer {
    public ??? GetProperty<T>() where T : IProperty<???> {
        //...
    }

Since T is the type of the property itself, we need another generic type parameter to get to the return type:

public class PropertyContainer {
    public U GetProperty<T, U>() where T : IProperty<U> {
        //...
    }

But all of a sudden, the call site is not so neat anymore, because both types must be specified:

container.GetProperty<SomeProperty, ReturnType>();

This bugged me for a while, until I finally realized that the solution is to let the property-getting method take a function delegate, and pass in a method group! A method group is simply a method name, meaning that there may be multiple overloaded methods in the group. But the compiler will determine which method to use based on the delegate signature. So, let’s scrap the IProperty interface and declare the method as follows:

public class PropertyContainer {
    public T GetProperty(Func<PropertyContainer, T> getter) {
        //...
    }

So the method accepts a delegate, or a function, that takes a PropertyContainer instance as argument and returns a value of some arbitrary type T. This is equivalent to the Get method of the now-scrapped IProperty interface! (Again, I’ve omitted the implementation, but this time it’s dictionary lookup with getter.Method as key.) We can now declare a number of properties as methods:

public class Properties {
    public static int RootProperty(PropertyContainer container) {
        return 42;
    }

    public static double DerivedProperty(PropertyContainer container) {
        return container.GetProperty(RootProperty) * 3.14;
    }
}

If you take a look at the call site in the DerivedProperty method, you can see that we use the method group RootProperty as our property constant, and there is no need to type cast the property value before multiplying. In other words, the solution is pretty much identical to the Java one but using a completely different mechanism. While we don’t have to type something like the “.class” suffix, we have to include the class name to use a property outside of the Properties class:

public void SomeMethod(PropertyContainer container) {
    Console.WriteLine(container.GetProperty(Properties.DerivedProperty));
}

While C# doesn’t have static imports like Java, it’s possible to use an using alias to shorten the class name a bit:

using P = SomePackage.Properties;
...

public void SomeMethod(PropertyContainer container) {
    Console.WriteLine(container.GetProperty(P.DerivedProperty));
}

Some final words

The two solutions are roughly equivalent from a usage perspective, in the sense that both require no unnecessary glue code to work. I was very happy when I found the C# method group solution, which IMHO is quite elegant! I hope you think so too!