带操作符的泛型值和类型比较器

本文关键字:类型 比较器 泛型 操作符 | 更新日期: 2023-09-27 18:04:52

我有一个业务逻辑,基于预定义的条件(OperatorType和比较值),验证它是真还是假。这里的问题是值是"类型化"的,并且带有操作符(大于/小于/等于等)。

如果ValueType为Integer,则先将值和比较值转换为Integer,再以OperatorType为基础进行比较。

我想知道我是否可以有一个通用函数,传递CompareValue, Value, ValueType, OperatorType并返回true/false。

using System;
using System.Collections.Generic;
namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var compare1 = 3;
            var foo1 = new Foo { Value = "2", OperatorType = OperatorTypes.GreaterOrEqual, ValueType = ValueTypes.Long };
            //compare compare1 and foo1.Value, output should be false (2 < 3)
            var compare2 = true;
            var foo2 = new Foo { Value = "True", OperatorType = OperatorTypes.Equal, ValueType = ValueTypes.Bool };
            //compare compare2 and foo2.Value, output should be true (true = true)
            var compare3 = DateTime.Parse("2013-03-19 15:00");
            var foo3 = new Foo { Value = "2013-03-19 16:00", OperatorType = OperatorTypes.Less, ValueType = ValueTypes.Date };
            //compare compare3 and foo3.Value, output should be false (2013-03-19 16:00 < 2013-03-19 15:00)
        }
    }
    public enum OperatorTypes : uint
    {
        Equal = 1,
        Greater = 2,
        GreaterOrEqual = 3,
        Less = 4,
        LessOrEqual = 5
    }
    public enum ValueTypes : uint
    {
        None = 0,
        Integer = 1,
        Long = 2,
        Numeric = 3,
        Date = 4,
        Text = 5,
        Bool = 6
    }
    class Foo
    {
        public string Value { get; set; }
        public ValueTypes ValueType { get; set; }
        public OperatorTypes OperatorType { get; set; }
    }
}

带操作符的泛型值和类型比较器

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Compare<double>("123.1", 125.3, (a, b) => a > b));
        Console.WriteLine(Compare<DateTime>("19/03/2013", DateTime.Now, (a, b) => a == b));
    }
    private static bool Compare<T>(string valueAsString, T valueToComapare, Func<T,T,bool> check)
    {
        var asObject = (T)Convert.ChangeType(valueAsString, typeof(T));
        if (asObject != null)
        {
            return check(asObject, valueToComapare);
        }
        return false;
    }
}

废话不多说,让我们开始吧:

using System;
using System.Diagnostics;
using System.Collections.Generic;
namespace Test
{
    class Program
    {
        public static dynamic CompareVal(Foo logic)
        {
            switch(logic.ValueType)
            {
                case ValueTypes.Integer: return Convert.ToInt32(logic.Value);
                case ValueTypes.Long:    return Convert.ToInt64(logic.Value);
                case ValueTypes.Numeric: return Convert.ToDecimal(logic.Value);
                case ValueTypes.Date:    return Convert.ToDateTime(logic.Value);
                case ValueTypes.Text:    return logic.Value;
                case ValueTypes.Bool:    return Convert.ToBoolean(logic.Value);
            }
            throw new InvalidProgramException("Unsupported ValueType");
        }
        public static bool Evaluate(dynamic val, Foo logic)
        {
            dynamic cmpval = CompareVal(logic);
            switch(logic.OperatorType)
            {
                case OperatorTypes.Equal:          return val == cmpval;
                case OperatorTypes.Greater:        return val >  cmpval;
                case OperatorTypes.GreaterOrEqual: return val >= cmpval;
                case OperatorTypes.Less:           return val <  cmpval;
                case OperatorTypes.LessOrEqual:    return val <= cmpval;
            }
            return false;
        }
        static void Main(string[] args)
        {
            //compare compare1 and foo1.Value, output should be false (2 < 3)
            Debug.Assert(false == Evaluate(3, new Foo 
                        { 
                            Value = "2", 
                            OperatorType = OperatorTypes.GreaterOrEqual, 
                            ValueType = ValueTypes.Long 
                        }));
            //compare compare2 and foo2.Value, output should be true (true = true)
            Debug.Assert(true == Evaluate(true, new Foo 
                        { 
                            Value = "True", 
                            OperatorType = OperatorTypes.Equal, 
                            ValueType = ValueTypes.Bool 
                        }));
            //compare compare3 and foo3.Value, output should be false (2013-03-19 16:00 < 2013-03-19 15:00)
            Debug.Assert(false == Evaluate(DateTime.Parse("2013-03-19 15:00"), new Foo 
                        { 
                            Value = "2013-03-19 16:00", 
                            OperatorType = OperatorTypes.Less, 
                            ValueType = ValueTypes.Date 
                        }));
        }
    }
    public enum OperatorTypes : uint
    {
        Equal = 1,
        Greater = 2,
        GreaterOrEqual = 3,
        Less = 4,
        LessOrEqual = 5
    }
    public enum ValueTypes : uint
    {
        None = 0,
        Integer = 1,
        Long = 2,
        Numeric = 3,
        Date = 4,
        Text = 5,
        Bool = 6
    }
    class Foo
    {
        public string Value { get; set; }
        public ValueTypes ValueType { get; set; }
        public OperatorTypes OperatorType { get; set; }
    }
}

这可以做很多改进(更好的类型检查、文化信息感知和错误处理)。但是,它是一个开始