2016-05-30 20 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を返すでしょう、にするために使用良い。しかし、今では、同じ種類の検証結果である「ソフト検証結果」を処理する必要がありますが、結果の数には含めるべきではありません。これは警告の一種で、IsSoftErrorIValidationResultに設定することで定義されます。バリデーターは、「ソフト検証結果」と「正規検証結果」の両方を得ることができます。

x検証結果と無制限のソフト検証結果を取得して、IsSoftError == trueのすべてのIValidationResultsがコレクションに含まれますが、カウントには含まれないようにします。私はそれが奇妙に聞こえることを知っていますが、xエラー後にファイルの検証を続ける必要はありませんが、検証によって無限の "警告"が返される可能性があります。

CPUが重いので、列挙型が複数回列挙されないようにすることが非常に重要です。以下は変更したいコードです。

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

、あなたはこれを試みることができる:第11回ハードエラーが発生したときに、これは停止する

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

+0

有望そうです。私は以前TakeWhileを使っていません。それを試して、あなたに戻ってくるでしょう... – smoksnes

+0

これはまさに私が探していたものでした。条件付テイク()。 :)私は愚かな/解決できない質問のように感じたので、私は質問を投稿したくなかったが、今私は嬉しいです。マヌエルありがとう。 – 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がMonad Functional Programmingに基づいていることを前提に、このアプローチを必要とする解決策をLinqに求めました。 – Aron