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:
| 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!