根据满足的范围运行不同的验证功能

时间:2016-12-28 20:43:30

标签: c# delegates

我需要运行一个不同的验证方法说:Method1(int datum),Method2(int datum)... Method5(int datum)取决于这个int属于哪个范围。

我管理这些范围的尝试现在看起来像这样(有很多,下面是简化):

List<Tuple<int,int>> ranges = new List<Tuple<int,int>>()
{
   new Tuple<int,int>(10000,25000),
   new Tuple<int,int>(30000, 80000),
   new Tuple<int,int>(85000, 90000) 
}

如何更改以上结构,以便将特定方法绑定到每个范围,以便我可以针对范围测试数据并运行与该范围关联的方法?

感谢您的任何意见。

2 个答案:

答案 0 :(得分:3)

这只是关于使用委托和字典,其中键是你的范围并重视方法:

public sealed class RangeOperationManager
{
    // A map of ranges to operations
    private Dictionary<Tuple<int, int>, Func<Tuple<int, int>, int, bool>> RangeToOperationMap { get; }
        = new Dictionary<Tuple<int, int>, Func<Tuple<int, int>, int, bool>>();

    // Encapsulates how to add new range to operation mappings. 
    // It's like a façade method.
    public void AddOperation(int min, int max, Func<Tuple<int, int>, int, bool> processor)
        => RangeToOperationMap[Tuple.Create(min, max)] = processor;

    public bool Operate(int input)
    {
        // We try to get an operation associated with a range based on the input
        var foundPair = RangeToOperationMap
            .SingleOrDefault
            (
                // Let's see if we find a range for the given input!
                pair => input >= pair.Key.Item1
                        && input <= pair.Key.Item2
            );

        // If this "if" evaluates true, it would mean that no range could be found
        //
        // NOTE: We need to check if retrieved pair isn't key-value pair default
        // value because it's an structure (value type).  
        if (!foundPair.Equals(default(KeyValuePair<Tuple<int, int>, Func<Tuple<int, int>, int, bool>>)))
        {
            // If some could be found, then we proceed to call the associated
            // delegate giving the range and input as arguments!
            return foundPair.Value(foundPair.Key, input);
        }
        else
        {
            throw new InvalidOperationException("Input couldn't match any of configured ranges");
        }
    }
}

...例如,上面的class可以按如下方式使用:

class Program
{
    // In some class who knows where...
    static bool Method1(Tuple<int, int> range, int input)
    {
        return true;
    }

    static bool Method2(Tuple<int, int> range, int input)
    {
        return true;
    }

    static bool Method3(Tuple<int, int> range, int input)
    {
        return true;
    }

    static void Main(string[] args)
    {
        RangeOperationManager rangeProcessor = new RangeOperationManager();
        rangeProcessor.AddOperation(10000, 25000, Method1);
        rangeProcessor.AddOperation(30000, 80000, Method2);
        rangeProcessor.AddOperation(85000, 90000, Method3);

        bool result1 = rangeProcessor.Operate(12300); // true
        bool result2 = rangeProcessor.Operate(35000); // true
        bool result3 = rangeProcessor.Operate(89000); // true
    }
}

进一步阅读

在C#7.0中会有syntactic sugar for tuples!我觉得我需要更新我的答案,以便在C#7.0及更高版本中使用语法集成元组的奇迹。

答案 1 :(得分:1)

您可以创建将范围和验证方法的集合作为参数的类,然后循环所有实例,直到找到有效范围并执行验证方法

public class Range
{
    public int Min { get; }
    public int Max { get; }

    public Range(int min, in max)
    {
        Min = min;
        Max = max;
    }
}

public class ValidateRanges
{
    private readonly List<Range> _ranges;
    private readonly Func<int, bool> _validate;

    public ValidateRanges(List<Range> ranges, Func<int, bool> validate)
    {
        _ranges = ranges;
        _validate = validate;
    }

    bool IsInRange(int value)
    {
        return _ranges.Any(range => value > range.Min && value < range.Max);
    }

    public bool Validate(int value)
    {
       return validate(value);
    }
}

然后在您的代码中使用

var validateranges = new[]
{
    new ValidateRanges(new[] {new Range(0, 100),new Range(1000, 1100)}, ValidationMethod1),
    new ValidateRanges(new[] {new Range(101, 200)}, ValidationMethod2),
    new ValidateRanges(new[] {new Range(201, 500)}, ValidationMethod3),
};

foreach (var validation in validateranges.Where(val => val.IsInRange(value)))
{
    return validation.Validate(value);
}

return false; // default validation