我怎样才能重写这段代码,以免看起来好像我正在使用异常作为流程控制的一种形式?

How could I rework this code so as not to appear as if I am using exceptions as a form of flow-control?

我听说异常和 try-catch 块不应该用于流控制,所以我想要一种方法来重写这段代码以避免出现这种情况。

我在 neuralNetwork class 中有一个方法 validateTrainingSets,它确实如其名称所暗示的那样 - 验证提供的训练集(除其他事项外,确保训练集中的输入数量匹配神经网络的输入数量,以及每个答案的输出数量与神经网络的最终输出数量匹配)。

因为验证失败的方式有很多种,我决定将抛出异常留给验证方法本身,函数可以抛出三种不同的自定义异常。

在允许 class 用户手动更新每层神经元数量的方法中,代码的最后一位验证 and/or 更新训练集(取决于是否有新的提供了训练集),我的问题是,我将如何改进它?

在下面的代码中,验证器中的 "true" 参数告诉验证器如果失败则将训练集设置为空。 (本意是如果用户没有提供新的训练集,但已有的训练集与新的排列一致则保留,否则丢弃)。

fldValidate 字段是一个标志,在代码的前面部分被设置为 false,我需要确保它被设置回 true,不考虑任何错误。

try { validateTrainingSets(fldTrainingSets, fldTrainingAnswers, true); }
catch(TrainingSetCardinalityMismatch) { }
catch(InputSetCardinlityMismatch) { }
catch(OutputAnswerCardinalityMismatch) { }
catch {
    fldValidate = true;
    throw;
}
finally { fldValidate = true; }

是的,我认为大多数审阅者会觉得这令人困惑并要求进行更改。如果我对问题的理解正确,您可以使用 enum 例如:

enum Validity { Valid, TrainingSetCardinalityMismatch, InputSetCardinalityMismatch, OutputAnswerCardinalityMismatch } 

class TrainingSet { 
    Validity Validate(TrainingAnswer[] trainingAnswers) { // ... etc ... } 
}

然后按照您认为最直观的方式进行分配,例如:

var validTrainingSets = 
    from trainingSet in fldTrainingSets 
    where trainingSet.Validate(fldTrainingSets) == Validity.Valid
    select trainingSet;

或:

var validTrainingSets = 
    fldTrainingSelects.Select(t => t.Validate(fldTrainingAnswers)).Filter(v => v == Validity.Valid); 

或:

Dictionary<Validity, List<TrainingSet>> groupedTrainingSets = 
    from trainingSet in fldTrainingSets   
    group trainingSet by trainingSet.Validate(fldTrainingAnswers) into validityGroup 
    select new { validityGroup.Key, validityGroup.ToList() } 

如果 enum 还不够,请尝试接口或抽象 class :

interface IValidity {}

class Valid : IValidity { // ... etc ... } 
class TrainingSetCardinalityMismatch : IValidity { public int ExpectedCardinality; // etc...  }