2016-05-30 2 views
1

У меня есть пара валидаторов, который проверяет IDeliveryObject, который концептуально может быть описан как файл с несколькими строками. Эта часть работает нормально.Условное взятие с LINQ

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 каждый валидатор будет возвращать только 10 validationresults, который имел обыкновение быть хорошо. Но теперь мне нужно обработать «мягкий результат проверки», который является тем же самым результатом проверки, но он не должен включаться в число полученных результатов. Это своего рода предупреждение, которое определяется установкой IsSoftError в IValidationResult. Валидатор может дать как «мягкий результат проверки», так и «регулярный результат проверки».

То, что я хочу, - это принять x результатов проверки + неограниченные результаты мягкой проверки, так что все IValidationResults с IsSoftError == true будут включены в коллекцию, но не в счете. Я знаю, что это звучит странно, но концепция заключается в том, что нет необходимости продолжать проверку файла после ошибок x, но проверка может возвращать неограниченные «предупреждения».

Очень важно, чтобы перечисление не было перечислить более одного раза, потому что оно тяжело для процессора. Ниже приведен код, который я хочу изменить.

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

EDIT: Когда я получил 10 ошибок 'жесткой' Я хочу, чтобы полностью остановить цикл. Основная проблема здесь заключается в том, что цикл не останавливается при возникновении 10 «мягких» ошибок.

+0

Вы хотите иметь максимум 10 не-мягких ошибок для каждого валидатора? Или вообще? –

+1

Если вы хотите получить все мягкие ошибки. то вы должны перечислить до конца, даже если вы достигнете 10 несимметричных ошибок. Это означает, что вы должны только отфильтровать окончательный результат в конце. Это может быть случай, когда есть некоторая мягкая ошибка после получения 100 не-мягких ошибок. –

+0

На самом деле в целом. Но решение, которое у меня есть, по-прежнему работает там, где я отслеживаю общее количество и добавляю еще 10 ошибок для каждого валидатора. Это не так важно, если это 10 + 10. – smoksnes

ответ

1

В случае, если вы хотите полностью остановить после ошибок 10 «Hard», вы можете попробовать это:

int count = 0; 
IEnumerable<IValidationResult> results = deliveryValidator.Validate(deliveryObject) 
    .TakeWhile(error => error.IsSoftError || count++ < maxNumberOfErrors); 

это остановится, когда столкнулся с 11 серьезной ошибки.

+0

Выглядит многообещающе. Раньше я не использовал TakeWhile. Попробуем и вернемся к вам ... – smoksnes

+0

Оказалось, что это именно то, что я искал. Условное значение Take(). :) Я не хотел публиковать этот вопрос, потому что это казалось глупым/неразрешимым вопросом, но теперь я рад, что сделал. Спасибо Мануэлю. – smoksnes

0
//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); 
+0

Я думаю, он хочет, чтобы оценка остановилась, как только произошли 10 'жестких' ошибок. –

+0

@ManuelSchweigert Но он должен продолжать получать мягкие ошибки. – Aron

+0

@ManuelSchweigert Также OP запросил решение в Linq, что позволило бы избежать этого подхода, учитывая, что Linq основан в функциональном программировании Monad. – Aron