方法重载还是更优雅的东西?
Method overloading or something more elegant?
我正在用 C# 编写一些代码,我注意到如下场景。我想知道如何才能使它更优雅、更易于维护。
如果我遇到以下超载情况
public void DoSmtg(string a) { DoSmtg(a, 0, 0f); }
public void DoSmtg(string a, int x) { DoSmtg(a, x, 0f); }
public void DoSmtg(string a, int x, double d) { // method logic }
说现在我需要添加另一个 bool 参数。我必须将其修改为
public void DoSmtg(string a) { DoSmtg(a, 0, 0f, false); }
public void DoSmtg(string a, int x) { DoSmtg(a, x, 0f, false); }
public void DoSmtg(string a, int x, double d, bool doIt) { // method logic }
这是一个非常简单的例子。可以说 DoSmtg() 方法还有 10 个版本。显然,这段代码有味道。虽然重载非常有效,但显然很难维护此代码,因为:
还有很多方法要写
在仔细调查之前调用哪个方法并不明显(特别是如果方法有更多参数)
方法被越来越多的参数列表污染
添加的新参数需要在很多地方进行更改(想想从许多不同位置调用的上述方法)
避免这种情况的优雅、简单且好的方法是什么?
您可以尝试将所有参数添加到一个函数中,使用默认值并在调用函数时命名参数:
public void DoSmtg(string a, int x=0, double d=0f, bool doIt=false) {
// method logic
}
调用该函数时,您将执行:
DoSmtg("yo!")
DoSmtg("yo!", d:0.59, doIt:true)
您可以将所有参数包装在一个 POCO 中:
public class SomethingParameters
{
public string A { get; set; }
public int X { get; set; }
public double D { get; set; }
public bool DoIt { get; set; }
}
那么方法签名变为:
public void DoSmtg(SomethingParameters parameters) { // method logic }
我喜欢这种模式,因为它在未来很容易扩展。如果您需要再添加五个参数,或者可选参数,没问题!
你可以这样称呼它:
var parameters = new SomethingParameters()
{
A = "foobar",
X = 123,
D = 0.123,
DoIt = false
}
DoSmtg(parameters);
如果您有很多代码调用您不想破坏的旧方法签名,您可以保留现有的重载但让它们调用新的重载:
public void DoSmtg(string a, int x, double d, bool doIt)
=> DoSmtg(new SomethingParameters()
{
A = a,
X = x,
D = d,
DoIt = doIt
});
我更喜欢使用单独的 class 作为参数。但是也许,正如您所说,您已经在多个地方调用了该方法并且不想修改它。
在这种情况下,您可以添加一个可选参数:
public void DoSmtg(string a, int x, double d, bool doIt = false)
除了您可以根据需要提供参数外,其他任何地方都无需更改。
如果您发现自己这样做,我仍然会使用 class 编写额外的重载并开始使用它。如果可选参数太多,可选参数也会开始变得混乱。
我正在用 C# 编写一些代码,我注意到如下场景。我想知道如何才能使它更优雅、更易于维护。
如果我遇到以下超载情况
public void DoSmtg(string a) { DoSmtg(a, 0, 0f); }
public void DoSmtg(string a, int x) { DoSmtg(a, x, 0f); }
public void DoSmtg(string a, int x, double d) { // method logic }
说现在我需要添加另一个 bool 参数。我必须将其修改为
public void DoSmtg(string a) { DoSmtg(a, 0, 0f, false); }
public void DoSmtg(string a, int x) { DoSmtg(a, x, 0f, false); }
public void DoSmtg(string a, int x, double d, bool doIt) { // method logic }
这是一个非常简单的例子。可以说 DoSmtg() 方法还有 10 个版本。显然,这段代码有味道。虽然重载非常有效,但显然很难维护此代码,因为:
还有很多方法要写
在仔细调查之前调用哪个方法并不明显(特别是如果方法有更多参数)
方法被越来越多的参数列表污染
添加的新参数需要在很多地方进行更改(想想从许多不同位置调用的上述方法)
避免这种情况的优雅、简单且好的方法是什么?
您可以尝试将所有参数添加到一个函数中,使用默认值并在调用函数时命名参数:
public void DoSmtg(string a, int x=0, double d=0f, bool doIt=false) {
// method logic
}
调用该函数时,您将执行:
DoSmtg("yo!")
DoSmtg("yo!", d:0.59, doIt:true)
您可以将所有参数包装在一个 POCO 中:
public class SomethingParameters
{
public string A { get; set; }
public int X { get; set; }
public double D { get; set; }
public bool DoIt { get; set; }
}
那么方法签名变为:
public void DoSmtg(SomethingParameters parameters) { // method logic }
我喜欢这种模式,因为它在未来很容易扩展。如果您需要再添加五个参数,或者可选参数,没问题!
你可以这样称呼它:
var parameters = new SomethingParameters()
{
A = "foobar",
X = 123,
D = 0.123,
DoIt = false
}
DoSmtg(parameters);
如果您有很多代码调用您不想破坏的旧方法签名,您可以保留现有的重载但让它们调用新的重载:
public void DoSmtg(string a, int x, double d, bool doIt)
=> DoSmtg(new SomethingParameters()
{
A = a,
X = x,
D = d,
DoIt = doIt
});
我更喜欢使用单独的 class 作为参数。但是也许,正如您所说,您已经在多个地方调用了该方法并且不想修改它。
在这种情况下,您可以添加一个可选参数:
public void DoSmtg(string a, int x, double d, bool doIt = false)
除了您可以根据需要提供参数外,其他任何地方都无需更改。
如果您发现自己这样做,我仍然会使用 class 编写额外的重载并开始使用它。如果可选参数太多,可选参数也会开始变得混乱。