I have two properties. I need to validate these properties against a rather large matrix showing compatible values.
Sample properties:
public string firstValue { get; set; }
public string lastValue { get; set; }
Sample matrix:
A B C
A X O O
B O X X
C X O X
Let the x axis represents the "firstValue" and the y axis represents the "lastValue". The program must validate that invalid combinations denoted by an "X" throw an error to the user.
Sample validation:
if (firstValue == "A")
{
if (lastValue == "A" || lastValue =="C)
Console.WriteLine("Invalid Combination");
}
This could obviously be refactored several ways using if\else and switch logic, but when you add many hundreds of values to the matrix it starts to get scary. I decided to create a new class containing one function per row in the matrix.
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");
}
}
}
Then I devised something like this to make sure I'm not hitting more code than I need to. The predicate will return a boolean selecting and invoking the validation method that needs to be run. (just a sample, not production code)
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;
}
This seems to work great, but I can't help thinking there's a better way. Any thoughts?
EDIT: Fabjan's answer is the one I'm going with for this particular problem. Thanks also to Tim Schmelter.
Create a 2d array and validate records with it using some method, something like:
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();
}
}
Output: