More Effective C# 12.使用選擇性引數減少方法的多載 More Effective C# 12.使用選擇性引數減少方法的多載(Use Optional Parameters to Minimize Method Overloads)

這個做法介紹使用 Optional Parameters 的好處與最好不要在方法中使用 Named Parameters 以及發佈後不要修改方法的參數名稱。

假設在 C# 中我有一個接受多個參數的方法,那麼在一般情況下就必須傳入所有引數,否則編譯器就會報錯,在下面的例子中假設我少傳一個 y 參數 那麼編譯就不會通過。

void Main()
{
	Console.WriteLine(Add(1, 2));
}

public int Add(int x, int y)
{
	return x + y;
}

你可能不想每次使用這個方法都帶入這兩個引數,這時候就幾個方式可以處理這個需求,第一個是使用方法多載的方式來達成。

void Main()
{
	Console.WriteLine(Add(1, 2));
}

public int Add(int x)
{
	return x + 2;
}

public int Add(int x, int y)
{
	return x + y;
}

但使用多載的方式會需要撰寫非常多的額外方法,所以就可以考慮使用 Optional Parameters 的方式把多個方法整合在一個裡面,原理是透過設定一個 預設值,這樣既使你只傳入一個參數 x,編譯器也能透過預設值了解參數 y 的內容。

void Main()
{
	Console.WriteLine(Add(1, 2));
}

public int Add(int x, int y = 2)
{
	return x + y;
}

但需要注意設定預設值的時候必須位於參數的最後方,或者有設定預設值的參數後面的參數也要有預設值。

void Main()
{
	Console.WriteLine(Add(1, 2, 3));
}

public int Add(int x, int y = 2, int z) // error
{
	return x + y + z;
}

那麼在參數越來越多的情況下,你想要跳過某幾個參數的話可以使用 Named Parameters 的方式來達成,也就是直接在呼叫的時候指定參數的姓名 來達到跳過參數的效果。

void Main()
{
	Console.WriteLine(Add(x: 1, z: 4));
}

public int Add(int x, int y = 2, int z = 3)
{
	return x + y + z;
}

另一個使用 Named Parameters 的好處是可以不用以正確的順序傳入方法引數,這樣能夠讓呼叫者以自己看著最容易理解的順序傳入引數,提升清晰度。

void Main()
{
	Console.WriteLine(Add(z: 4, y: 3, x: 2));
}

public int Add(int x, int y = 2, int z = 3)
{
	return x + y + z;
}

需要注意 Named Parameters 只是用來協助使用者理解程式用的,所以在編譯的時候編譯就就會把它重新排序回到正常的順序, 大概結果會像下面這樣把順序調整回來。

public class C
{
    public void M()
    {
        Console.WriteLine(Add(2, 3, 4));
    }

    public static int Add(int x, int y = 2, int z = 3)
    {
        return x + y + z;
    }
}

所以更換參數名稱後更新 patch 的場合中就不用擔心會破壞現有程式碼的運行,等到呼叫方重新編譯的時候才會發現你改了參數名稱導致編譯錯誤, 例如下面我把參數名稱改成 abc 之後發佈了一個函式庫版本,當你直接把新版本更新到運行中的程式時並不會導致錯誤,不過等到 你想要重新編譯的時候不會編譯成功,必須把 xyz 修改到新名稱。

void Main()
{
	Console.WriteLine(Add(z: 4, y: 3, x: 2));
}

public class Class1
{
    public static int Add(int a, int b = 2, int c = 3)
    {
        return a + b + c;
    }
}

不過修改預設值或是新增參數的時候就必須重新編譯,沒辦法用 patch 的模式帶入新的行為。

public static int Add(int x, int y = 2, int z = 13)
{
    return x + y + z;
}

Summary

這個做法建議多使用 Optional Parameters 取代眾多的多載方法,當你發佈新的函式庫版本時必須要注意不要影響到現有客戶呼叫的程式, 所以建議再提供而外的多載方法而不是直接修改參數的名稱。