There are two ways I'd deal with this, depending on the situation.
The first is to use an enum
and a Dictionary<TKey, TValue>
to map a character to an entry in the enum
.
enum Priority : byte
{
High,
Medium,
Low
}
static class Priorities
{
private static Dictionary<char, Priority> _toPriority = new Dictionary<char, Priority>();
private static Dictionary<Priority, char> _fromPriority = new Dictionary<Priority, char>();
static Priorities()
{
var priorities = Enum.GetNames(typeof(Priority));
var values = (Priority[])Enum.GetValues(typeof(Priority));
for (var i = 0; i < priorities.Length; i++)
{
_toPriority.Add(priorities[i][0], values[i]);
_fromPriority.Add(values[i], priorities[i][0]);
}
}
public static Priority GetPriority(string field)
{
Priority res;
if (!TryGetPriority(field, out res))
throw new ArgumentException("Invalid priority on field.", "field");
return res;
}
public static bool TryGetPriority(string field, out Priority priority)
{
if (field == null || field.Length == 0) { priority = default(Priority); return false; }
return _toPriority.TryGetValue(field[0], out priority);
}
public static char GetCode(Priority priority)
{
return _fromPriority[priority];
}
}
Another way to do this would be to create a struct
which creates itself in public static readonly fields.
struct Priority
{
public static readonly Priority High = new Priority('H');
public static readonly Priority Medium = new Priority('M');
public static readonly Priority Low = new Priority('L');
static Priority()
{
register(High);
register(Medium);
register(Low);
}
public static bool TryGetPriority(char code, out Priority priority)
{
return _map.TryGetValue(code, out priority);
}
public static Priority GetPriority(char code)
{
Priority priority;
if (!TryGetPriority(code, out priority))
throw new ArgumentException("Code doesn't represent an existing priority.", "code");
return priority;
}
public override int GetHashCode()
{
return _code.GetHashCode();
}
public override bool Equals(object obj)
{
if (!(obj is Priority)) return false;
return ((Priority)obj)._code == _code;
}
public override string ToString()
{
return _code.ToString();
}
public static implicit operator char(Priority @this) { return @this._code; }
public static explicit operator Priority(char code)
{
Priority result;
if (!_map.TryGetValue(code, out result))
throw new InvalidCastException();
return result;
}
private static readonly Dictionary<char, Priority> _map = new Dictionary<char, Priority>();
private static void register(Priority p)
{
_map.Add(char.ToLowerInvariant(p._code), p);
_map.Add(char.ToUpperInvariant(p._code), p);
}
private readonly char _code;
private Priority(char code) { _code = code; }
}
Method 1:
Pros: You only have to define the enum
the result will automatically update. You can access both the full name (enumInstance.ToString()
) and the code.
Cons: You need to explicitly call conversion methods to change between the char
and Priority
.
Method 2:
Pros: The type will implicitly convert to char
, and can be cast from char
.
Cons: You have to update both the calls to register
and the enum
to add or modify entries. You cannot access the full name of the field.
Both cons on method two can be resolved easily. The first can be resolved by using reflection to discover all public fields. The second by either adding it as parameter to the constructor or also through reflection.
Using method 1:
Priority p = Priority.High; // Assign literal
MessageBox.Show(p.ToString()); // High
MessageBox.Show(Priorities.GetCode(p).ToString()); // H
Priority p = Priorities.GetPriority('L'); // Cast from character
MessageBox.Show(p.ToString()); // Low
MessageBox.Show(Priorities.GetCode(p).ToString()); // L
Priority p; // Safe assigning
if (!Priorities.TryGetPriority('M', out p))
return;
MessageBox.Show(p.ToString()); // Medium
MessageBox.Show(Priorities.GetCode(p).ToString()); // M
Using method 2:
Priority p = Priority.High; // Assign literal
MessageBox.Show(p.ToString()); // H
Priority p = (Priority)'L'; // Cast from character
MessageBox.Show(p.ToString()); // L
Priority p; // Safe assigning
if (!Priority.TryGetPriority('M', out p))
return; // Handle invalid scenario
MessageBox.Show(p.ToString()); // M
Personally I think this solution is much cleaner than relying on two switches and the definition. Performance wise (it won't really matter unless you have an incredibly large database) it'll perform very similar to the switch statement. A switch statement in the right condition will be compiled an in-code hashmap, just like a Dictionary<TKey, TValue>
is a hashmap.
If you want to have multi-character strings just change char
to string
.