I love using mapper classes to avoid littering my code with ugly if/case statements. These classes simply map a string value to something else, like an enumeration value.
An example of one of the mapper classes in Noma looks like this:
public static class CascadeOptionMapper
{ private static readonly Dictionary<string, CascadeOption> _map = InitializeMap();
private static Dictionary<string, CascadeOption> InitializeMap()
{ Dictionary<string, CascadeOption> map = new Dictionary<string, CascadeOption>();
map.Add("none", CascadeOption.None); map.Add("save-update", CascadeOption.SaveUpdate); map.Add("all", CascadeOption.All); map.Add("delete", CascadeOption.Delete); map.Add("all-delete-orphan", CascadeOption.AllDeleteOrphan);
return map;
}
public static CascadeOption GetCascadeOption(string key)
{ if (string.IsNullOrEmpty(key) || !_map.ContainsKey(key))
{ return CascadeOption.Unknown;
}
return _map[key];
}
}
That's not a lot of code to keep your other code clean, but it does get repetitive if you need to do this for each mapper class. As you can see, the only thing that's not generic about the above class is adding the specific values to the map and returning a default value in case the key can't be found. We can move the other stuff to a generic base class, which would look like this:
public abstract class ValueMapper<T>
{ private readonly Dictionary<string, T> _map;
internal ValueMapper()
{ _map = new Dictionary<string, T>();
RegisterValues(_map);
}
protected abstract T ValueWhenKeyNotFound
{ get;
}
internal T GetValue(string key)
{ if (string.IsNullOrEmpty(key) || !_map.ContainsKey(key))
{ return ValueWhenKeyNotFound;
}
return _map[key];
}
protected abstract void RegisterValues(Dictionary<string, T> map);
}
The CascadeOptionMapper class now looks like this:
public class CascadeOptionMapper : ValueMapper<CascadeOption>
{ private static readonly CascadeOptionMapper _instance = new CascadeOptionMapper();
public static CascadeOption GetCascadeOption(string key)
{ return _instance.GetValue(key);
}
protected override CascadeOption ValueWhenKeyNotFound
{ get { return CascadeOption.Unknown; } }
protected override void RegisterValues(Dictionary<string, CascadeOption> map)
{ map.Add("none", CascadeOption.None); map.Add("save-update", CascadeOption.SaveUpdate); map.Add("all", CascadeOption.All); map.Add("delete", CascadeOption.Delete); map.Add("all-delete-orphan", CascadeOption.AllDeleteOrphan); }
}
The amount of code hasn't been reduced that much, but it has gotten easier to create a specific mapper now. And now i can easily add my other mapper classes:
public class PolymorphismOptionMapper : ValueMapper<PolymorphismOption>
{ private static readonly PolymorphismOptionMapper _instance = new PolymorphismOptionMapper();
public static PolymorphismOption GetPolymorphismOption(string key)
{ return _instance.GetValue(key);
}
protected override PolymorphismOption ValueWhenKeyNotFound
{ get { return PolymorphismOption.Unknown; } }
protected override void RegisterValues(Dictionary<string, PolymorphismOption> map)
{ map.Add("implicit", PolymorphismOption.Implicit); map.Add("explicit", PolymorphismOption.Explicit); }
}
public class OptimisticLockOptionMapper : ValueMapper<OptimisticLockOption>
{ private static readonly OptimisticLockOptionMapper _instance = new OptimisticLockOptionMapper();
public static OptimisticLockOption GetOptimisticLockOption(string key)
{ return _instance.GetValue(key);
}
protected override OptimisticLockOption ValueWhenKeyNotFound
{ get { return OptimisticLockOption.Unknown; } }
protected override void RegisterValues(Dictionary<string, OptimisticLockOption> map)
{ map.Add("none", OptimisticLockOption.None); map.Add("version", OptimisticLockOption.Version); map.Add("dirty", OptimisticLockOption.Dirty); map.Add("all", OptimisticLockOption.All); }
}