如何在不依赖副作用的情况下创建两个序列?

时间:2013-03-13 08:30:02

标签: c# sequence

假设您必须处理InputType序列,该序列生成两个类型为OutputType的类型,另一个类型为ErrorType

基本实现可能是:

class SeqProcessor {
  private IEnumerable<ErrorType> errorTypes;

  public SeqProcessor()
  {
    this.errorTypes = Enumerable.Empty<ErrorType>;
  }

  public IEnumerable<ErrorType> Errors
  {
    get { return this.errors; } 
  }

  public IEnumerable<OutputType> ProcessItems(IEnumerable<InputType> inputTypes)
  {
     yield return new OutputType();
     if (err) this.errorTypes = this.errorTypes.Concat(new ErrorType());
     yield return new OutputType();
     yield return new OutputType();
     if (err) this.errorTypes = this.errorTypes.Concat(new ErrorType());
     // ...
     yield break;
  }
}

我看到了这两个替代方案:

  • IProductOutputType之间使用通用界面(例如ErrorType),让ProcessItems返回IEnumerable<IProduct>(而不是使用Linq进行区分)

  • 定义名为ErrorType的{​​{1}}的子类,让NoError返回元组ProcessItems(如果没有错误,IEnumerable<Tuple<OutputType, ErrorType>>将在元组)。

修改

由于NoError在语义上与ErrorType不同,因此混合这些类型可能会违反单一责任原则。 代表的使用是否可以作为可接受的替代设计:

OutputType

在这种情况下,您使用哪种方法?

2 个答案:

答案 0 :(得分:2)

第二种方法表明NoError实例是NoError的特化;这在实践中很少是真实的。更有可能的是,两者之间的共享功能很小,使第一种方法更好。

答案 1 :(得分:1)

根据您想要达到的目标,我在这里看到了多种可能的解决方案:

  1. 继续使用原始实现(我将替换private IEnumerable<ErrorType> errorTypes,但允许您确定错误所属的项目)。在这种情况下,您遇到的错误将具有警告的重要性(这就是为什么我也更喜欢名称Warning),因为它们是分开的从实际结果来看。

  2. 对于两种结果类型(即输出和错误)使用公共接口只有在使用结果列表的其他函数才能真正使用错误输出时才有意义。我怀疑这是你的意图但imho,这将是有效的设计选择。

  3. 正如彼得所指出的那样,NoError的子类ErrorType真的很讨厌。 然而,更好的解决方案是使用ResultType作为NoErrorError类型的基础。这样,你真的有基类的专业化。不过,我想知道输出将包含错误。原始元素?已处理但无效的元素?空值?根据你想要实现的目标,这个可能是合理的,但这很难从给定的信息中分辨出来,说实话,我怀疑这是你想要的。

  4. OnError在很多情况下都是很好的做法,因为它可以提供很大的灵活性。但是,在这种情况下,您仍然需要考虑结果中的相应条目。 Imho,它可能是最好的选择,只是为了避免处理null或任何特殊值而简单地将其排除。

  5. 总而言之,似乎OnError方法似乎最有希望,即使其他信息可能会引导您采用其他提到的方法之一。