обогащение перечислений - возможно? - PullRequest
1 голос
/ 22 сентября 2019

Я ищу решение для хранения неизменяемых данных в моем коде вместо базы данных.В конкретном случае я хочу иметь дело с единицами.Вот пример для единиц веса (они не изменятся, поэтому их можно хранить в моем коде):

public class Unit
    {
        public Unit() { }

        public Unit(string name, string symbol, double factor, Unit baseUnit, UnitType unitType)
        {
            this.Name = name;
            this.Symbol = symbol;
            this.Factor = factor;
            this.BaseUnit = baseUnit;
            this.UnitType = unitType;
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public UnitType UnitType { get; set; }
        public string Symbol { get; set; }
        public string NamePlural { get; set; }
        public Unit BaseUnit { get; set; }
        public double Factor { get; set; }
    }



    public static class TimeUnits
    {
        public static Unit second = new Unit("second", "s", 1, null, UnitTypes.Time);
        public static Unit microsecond = new Unit("microsecond", "μs", 0.000001, second, UnitTypes.Time);
        public static Unit millisecond = new Unit("millisecond", "ms", 0.001, second, UnitTypes.Time);
        public static Unit minute = new Unit("minute", "min", 60.0, second, UnitTypes.Time);
        public static Unit hour = new Unit("hour", "h", 3600.0, second, UnitTypes.Time);
        public static Unit day = new Unit("day", "d", 24.0, hour, UnitTypes.Time);
        public static Unit week = new Unit("week", "w", 7, day, UnitTypes.Time);
    }

Как уже говорилось, я не хочу хранить эту неизменяемую информацию в БД в порядкечтобы избежать дополнительных союзов для ef-core при получении данных из базы данных.

В случае пола я просто использую enum:

 public enum Gender
{
    male = 1,
    female = 2,
    not_applicable = 9,
    dont_want_to_share = 10
}

Я хотел бы получить аналогичныйрешение для подразделений.Но у перечисления есть только идентификатор и имя.Для таких вещей, как показанные выше единицы измерения или другие случаи, мне нужны дополнительные свойства (например, factore, unitType и т. Д.).Большое спасибо за любой намек на то, как я смог добиться этого, чтобы ядро ​​загружало эти значения так же, как это делает с перечислениями.

Ответы [ 2 ]

2 голосов
/ 22 сентября 2019

Атрибуты - это один из подходов, но если вы хотите избежать использования отражения, вы можете реализовать класс, содержащий все, что вам нужно, что-то похожее на это:

public enum UnitType
{
    Second,
    Microsecond,
    Millisecond,
    Minute,
    Hour,
    Day,
    Week
}

public class Unit
{
    public string Name { get; private set; }

    public string Symbol { get; private set; }

    public double Factor { get; private set; }

    public Unit Base { get; private set; }

    public Unit(UnitType unit, bool isBase = false)
    {
        Name = GetUnitName(unit);

        Symbol = GetUnitSymbol(unit);

        Factor = GetUnitFactor(unit);

        if (!isBase)
            Base = GetUnitBase(unit);
    }

    private string GetUnitName(UnitType unit)
    {
        switch (unit)
        {
            case UnitType.Second:
                return "second";
            case UnitType.Microsecond:
                return "microsecond";
            case UnitType.Millisecond:
                return "millisecond";
            case UnitType.Minute:
                return "minute";
            case UnitType.Hour:
                return "hour";
            case UnitType.Day:
                return "day";
            case UnitType.Week:
                return "week";
            default:
                return null;
        }
    }

    private string GetUnitSymbol(UnitType unit)
    {
        switch (unit)
        {
            case UnitType.Second:
                return "s";
            case UnitType.Microsecond:
                return "μs";
            case UnitType.Millisecond:
                return "ms";
            case UnitType.Minute:
                return "min";
            case UnitType.Hour:
                return "h";
            case UnitType.Day:
                return "d";
            case UnitType.Week:
                return "w";
            default:
                return null;
        }
    }

    private double GetUnitFactor(UnitType unit)
    {
        switch (unit)
        {
            case UnitType.Second:
                return 1;
            case UnitType.Microsecond:
                return 0.000001;
            case UnitType.Millisecond:
                return 0.001;
            case UnitType.Minute:
                return 60.0;
            case UnitType.Hour:
                return 3600.0;
            case UnitType.Day:
                return 24.0;
            case UnitType.Week:
                return 7;
            default:
                return 0;
        }
    }

    private Unit GetUnitBase(UnitType unit)
    {
        switch (unit)
        {
            case UnitType.Microsecond:
                return new Unit(UnitType.Second, true);
            case UnitType.Millisecond:
                return new Unit(UnitType.Second, true);
            case UnitType.Minute:
                return new Unit(UnitType.Second, true);
            case UnitType.Hour:
                return new Unit(UnitType.Minute, true);
            case UnitType.Day:
                return new Unit(UnitType.Hour, true);
            case UnitType.Week:
                return new Unit(UnitType.Day, true);
            default:
                return null;
        }
    }


}

использование:

// initiate a new Unit instance. 
var unit = new Unit(UnitType.Week);

// Get values
var name = unit.Name;
var symbol = unit.Symbol;
var factor = unit.Factor;

// In case if some units doesn't have base
if (unit.Base != null)
{
    var baseName = unit.Base.Name;
    var baseSymbol = unit.Base.Symbol;
    var baseFactor = unit.Base.Factor;

}

Это простой пример, не полностью протестированный, он просто показывает вам другой подход, который может быть реализован.

Вы также можете использовать неявный оператор для получения значения. Пример:

public class Unit
{
  ......

    public static implicit operator double(Unit v) => v.Factor;

    public static implicit operator string(Unit v) => v.Symbol;

}

Неявное получение значения:

var symbol = (string) unit; // will return the v.Symbol
var factor = (double) unit; // will return the v.Factor

Кроме того, я не показываю UnitTypes.Time, поскольку в нем нет большого кода, но я думаю, что примеров и идей будет достаточно, чтобы высказать ваши мыслитолчок вам нужен.

2 голосов
/ 22 сентября 2019

Я не уверен, что именно вы хотите сделать, но я думаю, что атрибуты будут хорошим вариантом.Вы можете установить атрибуты для каждого поля перечисления юнитов, как это, и извлекать их отражением в любое время, когда это необходимо.

    [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
sealed class UnitTypeAttribute : Attribute
{
    public UnitType UnitType{ get; set; }
    public UnitAttribute(UnitType unitT)
    {
        UnitType= unitT;
    }
}

    enum Unit
{
    [UnitType(UnitTypes.Time)]
    Second,

    [UnitType(UnitTypes.Time)]
    MicroSecond,

    [UnitType(UnitTypes.Time)]
    Hour
}

, а затем, когда вы хотите получить его, используйте этот метод (можно сделатьуниверсальный)

       public static UnitType GetUnitTypeAttribute(Unit unit)
    {
        var memberInfo = typeof(Unit).GetMember(unit.ToString());
        var result = memberInfo[0].GetCustomAttributes<UnitTypeAttribute>(false)

        return ((UnitType)result).UnitType;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...