簡體   English   中英

驗證列表<string> args 在 C# 中動態</string>

[英]Validate a List<string> args dynamically in C#

鑒於:

  • 爭論數
  • 每個爭論的類型
  • List<string> args

假設我有一個List<string> args ,如下所示:

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

我想按如下方式驗證args ,我可以根據我的代碼的要求調用這些方法中的任何一種。

驗證方法:

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;
}

問題:如您所見,我最終將擁有無限數量的驗證方法。 有沒有辦法讓我只有一種驗證方法,例如下面? (可以處理所有可能的情況)

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;
}

然后我可以調用上面的方法isValid(args, 3, List<string>{"float", "Int32", "Double"})嗎? 但是我的通用方法出現錯誤,有人知道如何通用和動態地驗證數據類型嗎?

怎么樣:

public bool IsValid<TArg0>(List<string> args)
    => args.Length == 1
    && IsValidCore<TArg0>(args[0]);

public bool IsValid<TArg0, TArg1>(List<string> args);
    => args.Length == 2
    && IsValidCore<TArg0>(args[0])
    && IsValidCore<TArg1>(args[1]);

public bool IsValid<TArg0, TArg1, TArg2>(List<string> args)
    => args.Length == 3
    && IsValidCore<TArg0>(args[0])
    && IsValidCore<TArg1>(args[1])
    && IsValidCore<TArg2>(args[2]);

因此,您將使用IsValid<float, double, int>(args);而不是isValidOneFloatTwoDoubleThreeInt32(args) args);

等等,對於TArgN的一些小的上限N 那里的問題是:然后您需要一個基於泛型的解析器,但如果您只需要能夠通過檢查T來處理特定類型,那不一定太糟糕:

private static bool IsValidCore<T>(string value)
{
    if (typeof(T) == typeof(string)) return true;
    if (typeof(T) == typeof(int)) return int.TryParse(...);
    if (typeof(T) == typeof(float)) return float.TryParse(...);
    if (typeof(T) == typeof(double)) return double.TryParse(...);
    // etc for some finite number of types
    throw new NotSupportedException("Not considered: " + typeof(T).Name);
}

如果您對任意驗證器有這樣的方法,也許會有所幫助:

public static bool IsValid<T>(List<T> args, params Func<List<T>, bool>[] validators)
    => validators.All(validate => validate(args));

現在,您可以例如以這種方式驗證它:

bool isValid = IsValid(args, list => list.Count == 3);

或使用現有方法:

bool isValid = IsValid(args, isValidThreeStrings);

或兩者兼有:

bool isValid = IsValid(args, list => list.Count == 3, isValidThreeStrings);

或多個:

Func<List<string>, bool>[] allValidators = new Func<List<string>, bool>[]
{ 
    list => list.Count == 2, 
    list => float.TryParse(list[1], out float val), 
    isValidOneFloatTwoDoubleThreeInt32
};
bool isValid = IsValid(args, allValidators);

如果您喜歡它並希望將它重用於各種列表/數組/任何您可以創建這樣的擴展方法的東西。 請注意,它需要IEnumerable<T>

public static class EnumerableExtensions
{
    public static bool AreAllValid<T>(this IEnumerable<T> items, params Func<IEnumerable<T>, bool>[] validators)
        => validators?.All(validate => validate(items)) ?? throw new ArgumentNullException(nameof(validators));
}

我建議提取model ,讓它成為一個字典Type為鍵,驗證器Func為值:

 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  
 };

那么驗證器可以是:

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;
}

用法:

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

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

如果您想使用string s 而不是Type s,請稍微更改s_ValidatorsIsValid

  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) {
    ...
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM