我有这个 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; }
这使我们可以避免使用过多参数的构造函数并实现不变性。实际上它解决了所有问题(参数排序等)。然而:
就在那时,我感到困惑并决定写下这个问题:在 C# 中避免“参数过多”问题而不引入可变性的最直接方法是什么?是否可以为此目的使用只读结构,但 API 设计不差?
澄清:
更新
这里提供的答案有不同的优点/缺点。因此,我想将其转换为社区 wiki。我认为每个带有代码示例和优点/缺点的答案都会为将来的类似问题提供很好的指导。我现在正试图找出如何做到这一点。
框架中包含的一种风格通常是将相关参数分组到相关类中(但又存在可变性问题):
var request = new HttpWebRequest(a, b); var service = new RestService(request, c, d, e); var client = new RestClient(service, f, g); var resource = client.RequestRestResource(); // O params after 3 objects