Validate a List args dynamically in C#

Given:

  • Number of arguements
  • Type of each arguement
  • List<string> args

Let’s say I have a List<string> args as follows:

List<string> args = new List<string> { "1", "helloworld", "3" }

I want to validate args as follows , I can call any one of these methods as required by my code.

Validation Methods:

public bool isValidOneString(List<string> args)
{
      return args.Count() == 1;
}
public bool isValidTwoStrings(List<string> args)
{
      return args.Count() == 2;
}
public bool isValidThreeStrings(List<string> args)
{
      return args.Count() == 3;
}
public bool isValidOneStringTwoFloat(List<string> args)
{
      bool isValid = args.Count() == 2;
      if(!isValid) return false;

      float valueAfterParse;
      isValid = float.TryParse(args[1], out valueAfterParse);
      return isValid;
}
public bool isValidOneFloatTwoDoubleThreeInt32(List<string> args)
{
      bool isValid = args.Count() == 3;
      if(!isValid) return false;

      float valueAfterParse;
      isValid = float.TryParse(args[0], out valueAfterParse);
      if(!isValid) return false;

      Double valueAfterParse;
      isValid = Double.TryParse(args[0], out valueAfterParse);
      if(!isValid) return false;

      Int32 valueAfterParse;
      isValid = Int32.TryParse(args[0], out valueAfterParse);
      if(!isValid) return false;

      return isValid;
}

Problem: As you can see, I will eventually end up having infinite number of validation methods. Is there a way so that I can have only 1 validation method like for example below? (which can take care of all possible cases)

public bool isValid(List<string> args, int totalExpectedCountOfArgs, List<string> typesOfEachArg)
{
      bool isValid = args.Count() == totalExpectedCountOfArgs;
      if(!isValid) return false;
      
      int i = 0;
      foreach(string dataType : typesOfEachArg) {
           isValid = typeOf(dataType).TryParse(args[i], out typeOf(dataType)); //I AM GETTING ERROR HERE BECAUSE I DONT KNOW HOW TO GENERIFY THIS
           if(!isValid) return false;
           i++;
      }
      return true;
}

And then I can just call the above method isValid(args, 3, List<string>{"float", "Int32", "Double"}) ? But I am getting error in my generic method, anyone know how to validate datatypes generically and dynamically?

Answer

I suggest extracting model, let it be a dictionary with Type as a key, and validator Func as a value:

 private static Dictionary<Type, Func<string, bool>> s_Validators = 
   new Dictionary<Type, Func<string, bool>>() {
     {typeof(string), (x) => true },
     {typeof(int), (x) => int.TryParse(x, out var _) },
     {typeof(float), (x) => float.TryParse(x, out var _) },
     {typeof(double), (x) => double.TryParse(x, out var _) },  
      //TODO: add more type validators here  
 };

Then validator can be:

private static bool IsValid(IEnumerable<string> arguments, params Type[] signature) {
  if (null == arguments)
    return false; // or throw ArgumentNullException
  if (null == signature)
    return false;

  int index = 0;

  foreach (string arg in arguments) {
    // Too many arguments 
    if (index >= signature.Length)
      return false;  

    // For argument to be valid we should know type and pass validation
    if (!s_Validators.TryGetValue(signature[index++], out var validator) || 
        !validator(arg))
      return false;
  }    

  // if index < signature.Length we have too few arguments
  return index == signature.Length;
}

Usage:

  List<string> args = new List<string> { "1", "helloworld", "3" };

  bool isValid = IsValid(args, typeof(int), typeof(string), typeof(int));

If you want to have strings instead of Types change s_Validators and IsValid a bit:

  private static Dictionary<string, Func<string, bool>> s_Validators = 
    new Dictionary<string, Func<string, bool>>() {
      {"string", (x) => true },
      {"int", (x) => int.TryParse(x, out var _) },
       ...
  };      

  private static bool IsValid(IEnumerable<string> arguments, params string[] signature) {
    ...
  }