使用 LINQ 的条件获取
Conditional take with LINQ
我有几个验证器正在验证一个 IDeliveryObject
,它在概念上可以描述为一个包含多行的文件。那部分工作正常。
IEnumerable<IDeliveryValidator> _validators; // Populated in ctor. Usually around 20 different validators.
private IEnumerable<IValidationResult> Validate(IDeliveryObject deliveryObject)
{
var validationErrors = new List<IValidationResult>();
int maxNumberOfErrors = 10;
foreach (IDeliveryValidator deliveryValidator in _validators)
{
IEnumerable<IValidationResult> results = deliveryValidator.Validate(deliveryObject).Take(maxNumberOfErrors);
validationErrors.AddRange(results);
if (validationErrors.Count >= maxNumberOfErrors )
{
return validationErrors.Take(maxNumberOfErrors).ToList();
}
}
return validationErrors;
}
逻辑遍历几个验证器,它们都针对不同的事情验证文件。
验证器可以看起来像这样:
public IEnumerable<IValidationResult> Validate(IDeliveryObject deliveryObject)
{
using (var reader = File.OpenText(deliveryObject.FilePath))
{
int expectedLength = 10; // Or some other value.
string line;
while ((line = reader.ReadLine()) != null)
{
var lineLength = line.Length;
if (lineLength != expectedLength)
{
// yield an error for each incorrect row.
yield return new DeliveryValidationResult("Wrong length...");
}
}
}
}
ValidationResult
看起来像这样:
public class DeliveryValidationResult : ValidationResult, IValidationResult
{
public DeliveryValidationResult(bool isSoftError, string errorMessage) : base(errorMessage)
{
IsSoftError = isSoftError;
}
public DeliveryValidationResult(string errorMessage) : base(errorMessage)
{
}
public DeliveryValidationResult(string errorMessage, IEnumerable<string> memberNames) : base(errorMessage, memberNames)
{
}
public DeliveryValidationResult(ValidationResult validationResult) : base(validationResult)
{
}
public bool IsSoftError { get; set; }
}
public interface IValidationResult
{
string ErrorMessage { get; set; }
bool IsSoftError { get; set; }
}
感谢 Take(maxNumberOfErrors)
和 yield
每个验证器只会 return 10 个验证结果,这在过去是很好的。但是现在我需要处理"soft validation result",这是同一种验证结果,但它不应该包含在产生的结果数中。这是一种警告,通过在IValidationResult
中设置IsSoftError
来定义。验证器可以产生 "soft validation result" 和 "regular validation result".
我要的是取x个验证结果+无限个软验证结果,这样所有IValidationResults
和IsSoftError == true
都会被收录,但不会被统计。我知道这听起来很奇怪,但概念是在 x 错误后无需继续验证文件,但验证可以 return 无限制 "warnings".
Enumeration 的枚举次数不要超过一次,这一点很重要,因为它 CPU-heavy。下面是我要更改的代码。
private IEnumerable<IValidationResult> Validate(IDeliveryObject deliveryObject)
{
var validationErrors = new List<IValidationResult>();
int maxNumberOfErrors = 10;
foreach (IDeliveryValidator deliveryValidator in _validators)
{
// Here I want results to contain MAX 10 regular validation results, but unlimited soft validation results
IEnumerable<IValidationResult> results = deliveryValidator.Validate(deliveryObject).Take(maxNumberOfErrors);
validationErrors.AddRange(results);
if (validationErrors.Count(x => !x.IsSoftError) >= maxNumberOfErrors)
{
return validationErrors.Take(maxNumberOfErrors).ToList();
}
}
return validationErrors;
}
编辑:
当我遇到 10 'hard' 个错误时,我想完全停止循环。这里的主要问题是循环 在发生 10 'soft' 个错误时不会停止。
//Go through all the items and sort them into Soft and NotSoft
//But ultimately these are in memory constructs...so this is fast.
var foo = Validate(delivery).ToLookup(x => x.IsSoftError);
var soft = foo[true];
var hard = foo[false].Take(10);
var result = Enumerable.Concat(soft, hard);
如果您想在 10 'hard' 次错误后完全停止,您可以试试这个:
int count = 0;
IEnumerable<IValidationResult> results = deliveryValidator.Validate(deliveryObject)
.TakeWhile(error => error.IsSoftError || count++ < maxNumberOfErrors);
这将在遇到第 11 个硬错误时停止。
我有几个验证器正在验证一个 IDeliveryObject
,它在概念上可以描述为一个包含多行的文件。那部分工作正常。
IEnumerable<IDeliveryValidator> _validators; // Populated in ctor. Usually around 20 different validators.
private IEnumerable<IValidationResult> Validate(IDeliveryObject deliveryObject)
{
var validationErrors = new List<IValidationResult>();
int maxNumberOfErrors = 10;
foreach (IDeliveryValidator deliveryValidator in _validators)
{
IEnumerable<IValidationResult> results = deliveryValidator.Validate(deliveryObject).Take(maxNumberOfErrors);
validationErrors.AddRange(results);
if (validationErrors.Count >= maxNumberOfErrors )
{
return validationErrors.Take(maxNumberOfErrors).ToList();
}
}
return validationErrors;
}
逻辑遍历几个验证器,它们都针对不同的事情验证文件。
验证器可以看起来像这样:
public IEnumerable<IValidationResult> Validate(IDeliveryObject deliveryObject)
{
using (var reader = File.OpenText(deliveryObject.FilePath))
{
int expectedLength = 10; // Or some other value.
string line;
while ((line = reader.ReadLine()) != null)
{
var lineLength = line.Length;
if (lineLength != expectedLength)
{
// yield an error for each incorrect row.
yield return new DeliveryValidationResult("Wrong length...");
}
}
}
}
ValidationResult
看起来像这样:
public class DeliveryValidationResult : ValidationResult, IValidationResult
{
public DeliveryValidationResult(bool isSoftError, string errorMessage) : base(errorMessage)
{
IsSoftError = isSoftError;
}
public DeliveryValidationResult(string errorMessage) : base(errorMessage)
{
}
public DeliveryValidationResult(string errorMessage, IEnumerable<string> memberNames) : base(errorMessage, memberNames)
{
}
public DeliveryValidationResult(ValidationResult validationResult) : base(validationResult)
{
}
public bool IsSoftError { get; set; }
}
public interface IValidationResult
{
string ErrorMessage { get; set; }
bool IsSoftError { get; set; }
}
感谢 Take(maxNumberOfErrors)
和 yield
每个验证器只会 return 10 个验证结果,这在过去是很好的。但是现在我需要处理"soft validation result",这是同一种验证结果,但它不应该包含在产生的结果数中。这是一种警告,通过在IValidationResult
中设置IsSoftError
来定义。验证器可以产生 "soft validation result" 和 "regular validation result".
我要的是取x个验证结果+无限个软验证结果,这样所有IValidationResults
和IsSoftError == true
都会被收录,但不会被统计。我知道这听起来很奇怪,但概念是在 x 错误后无需继续验证文件,但验证可以 return 无限制 "warnings".
Enumeration 的枚举次数不要超过一次,这一点很重要,因为它 CPU-heavy。下面是我要更改的代码。
private IEnumerable<IValidationResult> Validate(IDeliveryObject deliveryObject)
{
var validationErrors = new List<IValidationResult>();
int maxNumberOfErrors = 10;
foreach (IDeliveryValidator deliveryValidator in _validators)
{
// Here I want results to contain MAX 10 regular validation results, but unlimited soft validation results
IEnumerable<IValidationResult> results = deliveryValidator.Validate(deliveryObject).Take(maxNumberOfErrors);
validationErrors.AddRange(results);
if (validationErrors.Count(x => !x.IsSoftError) >= maxNumberOfErrors)
{
return validationErrors.Take(maxNumberOfErrors).ToList();
}
}
return validationErrors;
}
编辑: 当我遇到 10 'hard' 个错误时,我想完全停止循环。这里的主要问题是循环 在发生 10 'soft' 个错误时不会停止。
//Go through all the items and sort them into Soft and NotSoft
//But ultimately these are in memory constructs...so this is fast.
var foo = Validate(delivery).ToLookup(x => x.IsSoftError);
var soft = foo[true];
var hard = foo[false].Take(10);
var result = Enumerable.Concat(soft, hard);
如果您想在 10 'hard' 次错误后完全停止,您可以试试这个:
int count = 0;
IEnumerable<IValidationResult> results = deliveryValidator.Validate(deliveryObject)
.TakeWhile(error => error.IsSoftError || count++ < maxNumberOfErrors);
这将在遇到第 11 个硬错误时停止。