【问题标题】:Is there a better way to write business logic to validate mutually exclusive codes?有没有更好的方法来编写业务逻辑来验证互斥代码?
【发布时间】:2015-07-09 13:32:41
【问题描述】:

我有两个属性。我需要针对显示兼容值的相当大的矩阵来验证这些属性。

示例属性:

public string firstValue { get; set; }
public string lastValue { get; set; }

样本矩阵:

    A   B   C
A   X   O   O
B   O   X   X
C   X   O   X

设x轴代表“firstValue”,y轴代表“lastValue”。程序必须验证用“X”表示的无效组合是否会向用户抛出错误。

样本验证:

if (firstValue == "A")
{
    if (lastValue == "A" || lastValue =="C)
        Console.WriteLine("Invalid Combination");
}

这显然可以使用 if\else 和 switch 逻辑以多种方式重构,但是当您向矩阵添加数百个值时,它开始变得可怕。我决定创建一个新类,在矩阵中每行包含一个函数。

public class MutuallyExclusiveValidation
{
    public void CheckA(string lastValue)
    {
        if (lastValue == "A" || lastValue == "C")
        {
            Console.WriteLine("Invalid Combination");
        }
    }

    public void CheckB(string lastValue)
    {
        if (lastValue == "B")
        {
            Console.WriteLine("Invalid Combination");
        }
    }

    public void CheckC(string lastValue)
    {
        if (lastValue == "B" || lastValue == "C")
        {
            Console.WriteLine("Invalid Combination");
        }
    }
}

然后我设计了这样的东西来确保我不会遇到比我需要的更多的代码。谓词将返回一个布尔值,选择并调用需要运行的验证方法。 (只是一个示例,不是生产代码)

    public static void CheckForMutuallyExclusiveValues(string firstValue, string lastvalue)
    {
        var allValidators = GetMutuallyExclusiveValidators(firstValue, lastvalue);
        var requiredValidators = allValidators.First(x => x.Key(firstValue));
        var validationClassInstance = new MutuallyExclusiveValidation();
        requiredValidators.Value(validationClassInstance);
    }

    public static Dictionary<Predicate<string>, Action<MutuallyExclusiveValidation>> GetMutuallyExclusiveValidators(string firstValue, string lastvalue)
    {
        var returnDictionary = new Dictionary<Predicate<string>, Action<MutuallyExclusiveValidation>>();
        Action<MutuallyExclusiveValidation> validation;
        Predicate<string> condition;

        validation = x => x.CheckA(lastvalue);
        condition = x => x == "A";
        returnDictionary.Add(condition, validation);

        validation = x => x.CheckB(lastvalue);
        condition = (x => x == "B");
        returnDictionary.Add(condition, validation);

        validation = x => x.CheckC(lastvalue);
        condition = (x => x == "C");
        returnDictionary.Add(condition, validation);

        return returnDictionary;
    }

这似乎很有效,但我不禁想到有更好的方法。有什么想法吗?

编辑:Fabjan 的答案是我要解决这个特定问题的答案。还要感谢 Tim Schmelter。

【问题讨论】:

  • 为什么x=c|y=b无效?
  • @TimSchmelter - 如果您引用矩阵,则无效组合(用“X”表示)为 AA、AC、BB、CB、CC
  • 为什么不能只创建一个二维布尔数组并检查它?
  • @TimSchmelter 我可能写错了,但 x 轴(从左到右)排在第一位。
  • @Tresto: 有没有什么逻辑,让你 f.e.不能使用相同的第一个/最后一个值,还是矩阵是用户任意/预定义的?

标签: c# business-logic


【解决方案1】:

创建一个二维数组并使用某种方法验证记录,例如:

class MyClass
{
    bool[,] matrix = new bool[,]
    {            
        {false, true, false},  // x1 y123
        {true, false, true},   // x2 y123
        {true, false, false},  // x3 y123
    };

    string[] xValues = { "A", "B", "C" };
    string[] yValues = { "A", "B", "C" };

    public bool IsValid(string value1, string value2)
    {
        return matrix[Array.IndexOf(xValues, value1), Array.IndexOf(yValues, value2)];
    }
}


class Program
{
    static void Main()
    {
        MyClass c = new MyClass();

        Console.WriteLine(c.IsValid("A", "A"));

        Console.WriteLine(c.IsValid("B", "C"));

        Console.WriteLine(c.IsValid("A", "C"));

        Console.ReadKey();
    }
}

输出:

【讨论】:

    【解决方案2】:

    您可以使用Dictionary&lt;string, HashSet&lt;string&gt;&gt; 将 X 值存储为键,并将所有无效的 Y 值存储为值。

    Dictionary<string, HashSet<string>> InvalidValues = new Dictionary<string, HashSet<string>> { 
        {"A", new HashSet<string>{"A", "C"}},
        {"B", new HashSet<string>{"B"}},
        {"C", new HashSet<string>{"B", "C"}}
    };
    

    现在您可以有效地检查给定的 x 和 y 值是否无效:

    var emptySet = new HashSet<string>();
    var invalidValues = allValues
        .Where(x => InvalidValues.TryGet(x.FirstValue, emptySet).Contains(x.LastValue));
    foreach (Value val in invalidValues)
        Console.WriteLine("Invalid Combination: {0}|{1}", val.FirstValue, val.LastValue);
    

    使用这个扩展来 linqify Dictionary.TryGetValue:

    public static TValue TryGet<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue = default(TValue))
    {
        TValue value;
        bool success = dict.TryGetValue(key, out value);
        if (success)
            return value;
        else
            return defaultValue;
    }
    

    这个类:

    public class Value
    {
        public string FirstValue { get; set; }
        public string LastValue { get; set; }
    }
    

    还有一些样本值:

    var allValues = new List<Value> { 
        new Value { FirstValue = "A", LastValue = "C" }, 
        new Value { FirstValue = "A", LastValue = "B" }, 
        new Value { FirstValue = "B", LastValue = "C" }, 
        new Value { FirstValue = "A", LastValue = "A" } 
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-14
      • 1970-01-01
      • 2011-03-10
      • 1970-01-01
      • 2020-09-06
      • 2022-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多