![](/img/trans.png)
[英]How to validate list of string using EmailAddressAttribute in C#?
[英]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_Validators
和IsValid
:
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.