Java-esque Enums in .NET

In the process of porting some code from an existing Java application to C#, I came across the following enum:

public enum UnitType
{
    APT("Apartment"),
    BOX("Box"),
    LOT("Lot"),
    PIER("Pier"),
    RM("Room"),
    RR("Rural Route"),
    SLIP("Slip"),
    ST("Street"),
    STE("Suite"),
    UNIT("Unit"),
    WHARF("Wharf"),
    WING("Wing");
 
    private String label;
 
    UnitType(String label)
    {
        this.label = label;
    }
 
    public String getLabel()
    {
        return label;
    }
}

That's all well and good, but .NET enums are not full-blown objects as they are in Java. Since I really just need key-value associations in this case, a Dictionary would fit the bill here. But what about the calling code? It would be nice not to muddy things up with extraneous explicit trips to said dictionary. Let's apply some extension method magic…

public enum UnitType
{
    APT, BOX, LOT, PIER, RM, RR, SLIP, ST, STE, UNIT, WHARF, WING
}

public static class UnitTypeExtensions
{
    public static String GetLabel(this UnitType enumValue)
    {
        return UnitTypeLabels[key: enumValue];
    }

    private static IDictionary<UnitType, string> UnitTypeLabels = 
        new Dictionary<UnitType, string>
        {
            { UnitType.APT  , "Apartment" },
            { UnitType.BOX  , "Box" },
            { UnitType.LOT  , "Lot" },
            { UnitType.PIER , "Pier" },
            { UnitType.RM   , "Room" },
            { UnitType.RR   , "Rural Route" },
            { UnitType.SLIP , "Slip" },
            { UnitType.ST   , "Street" },
            { UnitType.STE  , "Suite" },
            { UnitType.UNIT , "Unit" },
            { UnitType.WHARF, "Wharf" },
            { UnitType.WING , "Wing" }
        };
}

Perfect. Without adding too much code, requesting mapped labels is now a part of UnitType's API:

string label = UnitType.APT.GetLabel(); // label value is "Apartment"

Loading Persisted Null Values Into Objects with MyBatis

It almost makes sense: only invoke that setter if there's a value to invoke it with. But what about when a null value is meaningul? From org.apache.ibatis.executor.resultset.FastResultSetHandler:

  protected boolean applyPropertyMappings(ResultSet rs, ResultMap resultMap, List<string> mappedColumnNames, MetaObject metaObject, ResultLoaderMap lazyLoader) throws SQLException {
    boolean foundValues = false;
    final List<resultmapping> propertyMappings = resultMap.getPropertyResultMappings();
    for (ResultMapping propertyMapping : propertyMappings) {
      final String column = propertyMapping.getColumn();
      if (propertyMapping.isCompositeResult() || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))) {
        Object value = getPropertyMappingValue(rs, metaObject, propertyMapping, lazyLoader);
        if (value != null) {
          final String property = propertyMapping.getProperty();
          metaObject.setValue(property, value);
          foundValues = true;
        }
      }
    }
    return foundValues;
  }

A javabean with a default value for one of its properties certainly won't benefit from this logic. Ignoring the persisted null will lead to an improperly reconstituted instance where the getter will return the assigned default value instead of null—not particularly helpful. What are the alternatives?

Reconstitute via a specialized constructor

On the one hand, this is a good place to enforce proper state when bringing the instance back, and writing a test against this setup would be a walk in the park. On the flip side, this will get ugly real fast as the realization that 30 args is a few too many sets in. And the lack of named parameters in Java won't help make those tests any more readable.

Don't assign default values in Javabeans

Given that MyBatis facilitates the DTO approach, we could fully embrace the idiom and dumb classes all the way down. The silver lining here is that defaults can be fully externalized into configuration, producing cleaner code along that particular axis.

Patch the framework to call mapped setters unconditioanlly

Not for the faint of heart. This will result in an overarching maintenance commitment to a third-party library. Perhaps submitting said patch to the framework developers will yield a fruitful bounty and usher in a new utopia for other programmers around the world. Or perhaps I should get back to actually producing tangible results today.