简体   繁体   中英

typesafe enum and implicit operator

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM