public static T GetBase <T>()
        {
            Type type   = typeof(T);
            var  fields = type.GetFields(BindingFlags.Public | BindingFlags.Static);

            for (int i = 0; i < fields.Length; i++)
            {
                ConversionAttribute attribute = fields[i].GetCustomAttribute <ConversionAttribute>();
                if (attribute.Operation == ConversionOperation.Base)
                {
                    return((T)fields[i].GetRawConstantValue());
                }
            }
            return(default);
        private static Expression ToBaseExpression(ConversionAttribute attribute, Expression value)
        {
            if (attribute.Operation == ConversionOperation.Base)
            {
                return(value);
            }

            Expression firstOperation = OperationToExpression(value, attribute.Operation, attribute.Factor, attribute.ConversionInterface);

            if (attribute.SecondOperation == ConversionOperation.None)
            {
                return(firstOperation);
            }
            else
            {
                return(OperationToExpression(firstOperation, attribute.SecondOperation, attribute.SecondFactor));
            }
        }
        private static Expression FromBaseExpression(ConversionAttribute attribute, Expression value)
        {
            if (attribute.Operation == ConversionOperation.Base)
            {
                return(value);
            }

            Expression secondExpression;

            if (attribute.SecondOperation == ConversionOperation.None)
            {
                secondExpression = value;
            }
            else
            {
                secondExpression = OperationToReverseExpression(value, attribute.SecondOperation, attribute.SecondFactor);
            }

            return(OperationToReverseExpression(secondExpression, attribute.Operation, attribute.Factor, attribute.ConversionInterface));
        }
        public static Func <double, T, double> GenerateConversion <T>(bool direct)
        {
            Type type           = typeof(T);
            var  valueParameter = Expression.Parameter(typeof(double), "value");
            var  unitParameter  = Expression.Parameter(type, "unit");
            var  returnTarget   = Expression.Label(typeof(double));

            //get fields and prepare cases for switch
            var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static);
            var cases  = new SwitchCase[fields.Length];

            for (int i = 0; i < fields.Length; i++)
            {
                ConversionAttribute attribute = fields[i].GetCustomAttribute <ConversionAttribute>();
                Expression          unit      = Expression.Constant(Enum.ToObject(type, fields[i].GetRawConstantValue()));
                Expression          convertor = direct ? ToBaseExpression(attribute, valueParameter) : FromBaseExpression(attribute, valueParameter);
                var returnStatement           = Expression.Return(returnTarget, convertor);
                cases[i] = Expression.SwitchCase(returnStatement, new Expression[] { unit });
            }

            //prepare default method throwing exception
            var constructorInfo   = typeof(ArgumentException).GetConstructor(new Type[] { typeof(string), typeof(string) });
            var argumentException = Expression.New(constructorInfo, new Expression[] { Expression.Constant("Unknown unit"), Expression.Constant("unit") });
            var defaultBody       = Expression.Throw(argumentException);

            //switch statement
            var switchStmt = Expression.Switch(unitParameter, defaultBody, cases);

            //method body
            var body = Expression.Block(typeof(double), new Expression[] { switchStmt, Expression.Label(returnTarget, Expression.Constant(0.0)) });

            //function
            var expression       = Expression.Lambda(typeof(Func <double, T, double>), body, new ParameterExpression[] { valueParameter, unitParameter });
            var functionDelegate = expression.Compile();

            return((Func <double, T, double>)functionDelegate);
        }