以前我有這樣的方法:
public void Test(string a, string b = null, int? c = null, string d = null)
重新設計后,我們決定將所有可選引數分組到一個類中,如下所示:
public class TestOptions
{
public TestOptions()
{
}
public string b { get; set; }
public int? c { get; set; }
public string d { get; set; }
}
所以方法內部實作不會改變,但簽名會變成:
public void Test(string a, TestOptions options = null)
我的問題是,既然第一個帶有三個可選引數的方法已經在使用,如果我現在想添加這個新方法,我應該如何通過多載來實作向后兼容?
uj5u.com熱心網友回復:
這取決于您是否關心代碼兼容性與二進制兼容性;后者通常是強制性的(為了不破壞編譯的代碼),但前者可以更靈活一些。
您不能只添加新的多載,因為 thenTest("abc")是模棱兩可的并且不再編譯。
編輯:如 canton7 注釋:您可以添加一種Test(string a)方法來避免這種歧義,但是:其他方法仍然存在(見下文),這進一步使 API 表面復雜化。
如果我們只關心二進制兼容性,我們可以這樣做:
public void Test(string a, string b, int? c, string d)
=> Test(a, new TestOptions { ... }); // forwarded
public void Test(string a, TestOptions options = null) { ... }
但這會破壞代碼兼容性,因為現有代碼Test("abc", "def")不再編譯。我們不能只強制第二個引數,因為如果這樣做,現有代碼Test("abc", c: 42)將不再編譯。
如果你關心最好的代碼兼容性,老實說,最好的選擇是不做optionsoptional。例如:
public void Test(string a, string b, int? c, string d)
=> Test(a, new TestOptions { ... }); // forwarded
public void Test(string a, TestOptions options) { ... }
這解決了幾乎所有的代碼兼容性問題。還有一個極端情況:Test("abc", null)- 所以:你有多在乎這個?
uj5u.com熱心網友回復:
如果你問如何多載第二個簽名,應該這樣做:
public void Test(string a, TestOptions options = null) =>
Test(a, options?.b, options?.c, options?.d);
但是,我質疑您是否需要現代 C# 中的額外類。如果這是一個簡潔明了的問題(即,您只需要提供后一個引數并且您也提供所有其他引數),您可以簡單地使用命名引數呼叫:
Test("meep", d: "moop");
uj5u.com熱心網友回復:
您可以將其更改TestOptions為struct. 但是你不能在你的多載中應用它作為一個可以為空的引數。
public struct TestOptions
{
public string b { get; set; }
public int? c { get; set; }
public string d { get; set; }
}
添加具有此類不可為空的結構引數的多載
public static void Test(string a, TestOptions options)
{ }
有了這些,下面的呼叫就不會模棱兩可了。
兩者都將呼叫舊的/第一個Test(string a, string b = null, int? c = null, string d = null)方法,保留最初的意圖,就像在這個新的多載到位之前一樣。
Test("ab");
Test("ab", null);
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/465761.html
上一篇:在單個linq查詢中的串列中列出
