我有这个API函数:
public ResultEnum DoSomeAction(string a, string b, DateTime c, OtherEnum d,
string e, string f, out Guid code)
我不喜欢 因为参数顺序变得不必要地重要。添加新字段变得越来越困难。很难看到正在传递的内容。很难将方法重构为较小的部分,因为这会带来在子函数中传递所有参数的另一项开销。代码更难读。
我想到了一个最明显的想法:让一个对象封装数据并将其传递,而不是一个个地传递每个参数。这是我想出的:
public class DoSomeActionParameters
{
public string A;
public string B;
public DateTime C;
public OtherEnum D;
public string E;
public string F;
}
这使我的API声明减少为:
public ResultEnum DoSomeAction(DoSomeActionParameters parameters, out Guid code)
真好 看起来很无辜,但实际上我们进行了巨大的更改:我们引入了可变性。因为我们之前所做的实际上是在堆栈上传递一个匿名的不可变对象:函数参数。现在我们创建了一个非常可变的新类。我们创建了一种操作调用者状态的功能。糟透了。现在我希望我的对象是不变的,我该怎么办?
public class DoSomeActionParameters
{
public string A { get; private set; }
public string B { get; private set; }
public DateTime C { get; private set; }
public OtherEnum D { get; private set; }
public string E { get; private set; }
public string F { get; private set; }
public DoSomeActionParameters(string a, string b, DateTime c, OtherEnum d,
string e, string f)
{
this.A = a;
this.B = b;
// ... tears erased the text here
}
}
如您所见,我实际上重新创建了最初的问题:参数太多。显然,这不是要走的路。我该怎么办?实现这种不变性的最后一个选择是使用如下所示的“只读”结构:
public struct DoSomeActionParameters
{
public readonly string A;
public readonly string B;
public readonly DateTime C;
public readonly OtherEnum D;
public readonly string E;
public readonly string F;
}
这使我们可以避免构造函数使用太多参数并实现不变性。实际上,它解决了所有问题(参数订购等)。然而:
- 每个人(包括FXCop和Jon Skeet)都同意 公开公共领域是不好的。
- 埃里克·利珀特(Eric Lippert)等人说,依靠只读字段实现不变性是一个谎言。
那时候我感到困惑,决定写这个问题:C#中最简单的方法是在不引入可变性的情况下避免“参数过多”的问题?可以使用只读结构来实现此目的,但又不会有不好的API设计吗?
说明:
- 请假设没有违反单一责任原则。在我的原始情况下,该函数只是将给定的参数写入单个DB记录。
- 我没有在寻找给定功能的特定解决方案。我正在寻求针对此类问题的通用方法。我对解决“参数过多”问题特别感兴趣,而又不会引入可变性或糟糕的设计。
更新
此处提供的答案具有不同的优点/缺点。因此,我想将其转换为社区Wiki。我认为每个带有代码示例和优点/缺点的答案都将为将来解决类似问题提供很好的指南。我现在正试图找出方法。
DoSomeActionParameters
是一个一次性对象,在方法调用后将其丢弃,因此我看不到这是一个问题。