I created a Unit
class that implements the typesafe
enum pattern. I implemented an implicit operator
in it to simplify its usage. But I want to refactor the implicit operator from string
to Unit
. Currently, I'm using a switch
block but this will get huge pretty quick once I add more units. My current code looks like this.
[DataContract]
public class Unit
{
public static readonly Unit USFeet = new Unit("US Feet", 1);
public static readonly Unit Meters = new Unit("Meters", 0.3048006096);
[DataMember] public double ConversionConstant { get; private set; }
[DataMember] private string Name { get; set; }
private Unit(string name, double conversionConstant)
{
Name = name;
ConversionConstant = conversionConstant;
}
public override string ToString()
{
return Name;
}
public static implicit operator string(Unit unit)
{
return unit.Name;
}
public static implicit operator Unit(string name)
{
switch (name)
{
case "US Feet":
return USFeet;
case "Meters":
return Meters;
default:
return null;
}
}
}
So my question is, is there a better way to approach this instead of using a switch
block?
I tried something like this but it doesn't work...
public static SortedList<string, Unit> UnitList = new SortedList<string, Unit>();
private Unit(string name, double conversionConstant)
{
Name = name;
ConversionConstant = conversionConstant;
UnitList.Add(name, this);
}
public static implicit operator Unit(string name)
{
return UnitList[name];
}
You can build a lookup table, and update it from the .ctor
:
private static Dictionary<string, Unit> definedUnits = new Dictionary<string, UserQuery.Unit>();
private Unit(string name, double conversionConstant)
{
Name = name;
ConversionConstant = conversionConstant;
definedUnits.Add(name, this);
}
public static implicit operator Unit(string name)
{
Unit result;
return definedUnits.TryGetValue(name, out result) ? result : null;
}
You can also build that table dynamically with reflection :
private static Dictionary<string, Unit> definedUnits = typeof(Unit)
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(x => x.IsInitOnly && x.FieldType == typeof(Unit))
.ToDictionary(x => x.Name, x => (Unit)x.GetValue(null));
It seems that what I tried above will work when done like this (I believe it's called lazy initialization)
[DataContract]
public class Unit
{
public static readonly Unit USFeet = new Unit("US Feet", 1);
public static readonly Unit Meters = new Unit("Meters", 0.3048006096);
private static Dictionary<string, Unit> _unitList;
public static readonly Dictionary<string, Unit> UnitList = _unitList ?? (_unitList = new Dictionary<string, Unit>());
[DataMember] private readonly double _conversionConstant;
[DataMember] private readonly string _name;
private Unit(string name, double conversionConstant)
{
_name = name;
_conversionConstant = conversionConstant;
UnitList.Add(name, this);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.