[英]Splitting/Combining Partial Methods
我了解部分方法可用於將方法的定義拆分到多個文件中。 我很好奇是否允許跨多個文件的方法的每個定義都包含代碼?
例如,假設我有一個方法private partial void Foo()
。 假設我已經在文件 A 和文件 B 中定義了它。這兩個實例都可以在方法中包含代碼,還是只有一個或另一個? 如果允許,我想我會感到驚訝。
不,你不能。 如果可以,當您調用Foo()
時,哪個代碼會首先執行? 如果兩個版本都在處理(和修改)全局狀態,那么了解執行順序將非常重要。
無論如何,這沒有任何意義。 所以不,你不能。
作為從這種可能性中出現的不穩定行為的潛在討厭的一個簡單示例,假設您可以,並且假設您有以下代碼:
public partial class MyClass {
private int count = 0;
public partial void NastyMethod() {
count++;
}
}
public partial class MyClass {
public partial void NastyMethod() {
Console.WriteLine(count);
}
}
當您調用NastyMethod()
時,它會打印什么值? 沒道理!
現在又一個奇怪的問題。 參數怎么辦? 並返回值?
public partial class MyClass2 {
public partial bool HasRealSolution(double a, double b, double c) {
var delta = b*b - 4*a*c;
return delta >= 0;
}
}
public partial class MyClass2 {
public partial void HasRealSolution(double a, double b, double c) {
return false;
}
}
而現在,人們怎么可能理解這段代碼呢? 調用HasRealSolution(1, 2, 1)
后我們應該考慮哪個返回? 怎么可能有 2 個不同的、同時的返回值*用於單個方法? 我們不是在處理不確定的有限自動機!
對於那些在這個假設的世界中強加我不存在的部分方法應該是void
的人,用在該類的某個私有字段上設置一個值來替換return
s。 效果幾乎一樣。
*注意我這里說的不是一個由兩個值組成的單個返回值,比如一個Tuple。 我在這里談論兩個返回值。 (???)
這確實是對@Bruno 答案的評論,可能與問題不完全相關:
不允許部分方法具有多個實現的決定是在語言設計中做出的任意決定。 您的論點是您可能決定不允許在您的語言中允許這樣的事情的一個很好的理由,但實際上並沒有技術限制。 您可以很容易地決定允許多個實現,並讓編譯器決定實現的執行順序。 實際上,C# 規范已經有partial
類的未定義順序的情況:
// A.cs:
partial class Program {
static int x = y + 42;
static void Main() {
System.Console.WriteLine("x: {0}; y: {1}", x, y);
}
}
// B.cs:
partial class Program {
static int y = x + 42;
}
根據 C# Specification v3.0,這是有效的 C#,但輸出可以是:
x: 42; y: 84
或者
x: 84; y: 42
並且允許編譯器生成它們中的任何一個。 它甚至不會產生警告。
C# 語言需要部分方法才能具有void
返回類型。 部分方法簽名最多可以定義一次。 同樣,該實現最多只能定義一次。
不可以。只有部分方法的單個版本可能包含代碼。 使用實現定義多個部分方法的實現將導致編譯器錯誤。
不,這是不可能的。 另外,你有一點誤解。 部分方法的目的不是“將方法的定義拆分到多個文件中”。
相反,部分方法旨在將類的定義拆分到多個文件中。 這很有幫助,特別是對於自動生成的代碼,因為它允許您定義“可選”方法,您可以自由實現,但也可以自由忽略。
正如一位響應者所指出的,在部分類的多個部分中排除多個部分方法實現沒有技術原因。 它現在很流行,甚至根據 Microsoft 文檔創建將在 Silverlight 中運行的程序集,也可以在完整的 CLR 下運行,具體取決於包含的文件。 Microsoft 自己的示例包括 Silverlight 兼容文件中的部分方法定義,其實現包含在 CLR 構建中包含的其他文件中。
當然,如果允許多個實現,開發人員必須意識到調用順序是不確定的這一事實。 一個例子是一種方法,它對一個布爾值進行單一引用,該布爾值表明當前環境能夠做“某事”。
一個例子:
/// <summary>
/// Method will determine whether a type is serializable.
/// </summary>
/// <param name="type">
/// The Type to be checked for serializability.
/// </param>
/// <param name="serializable">
/// ref variable to be set to <c>true</c> if serializable. If
/// <paramref name="serializable"/> is already <c>true</c>, the
/// method should simply return.
/// </param>
static partial void IsTheTypeSerializable(Type type, ref Boolean serializable);
此方法可用於實現包含多個類型序列化選項的框架,具體取決於混合了部分類的哪些部分以及包含哪些序列化程序。 即使只有一個實現(編譯器規則下的所有實現),實現也必須遵循上述方法文檔中描述的邏輯,因為無法保證該方法將在定義部分的哪一點出現調用。 如果允許多個實現,則整體邏輯必須保證結果不會依賴於實現的調用順序。
在我們的框架中,我們實際上使用可加載委托來執行不同場景的可序列化分析。 但是,實際上,為這種情況允許多種實現會很方便。
我們推測,微軟擔心如果新手開發人員被放任使用這個危險的功能會導致混亂。 人們需要知道這樣的事情是關於什么的。
這是不可能的。 您在一個地方定義簽名,在另一個地方定義實現。
有關詳細信息,請參閱MSDN 。
您不能合並方法,但可以使用部分方法設置鏈。 如果您想避免代碼編織,這是一個選項。 我並不是說這是一個很好的選擇,但它是一個選擇。
public partial class MyClass {
private int count = 0;
public partial void NastyMethod() {
count++;
}
}
public partial class MyClass {
public partial void NastyMethod() {
Console.WriteLine(count);
}
}
更改為。
public partial class MyClass {
private int count = 0;
public partial void NastyMethod() {
count++;
OnNastyMethodExecuted(count);
}
partial void OnNastyMethodExecuted(int Value);
}
public partial class MyClass {
partial void OnNastyMethodExecuted(int value) {
Console.WriteLine(value);
}
}
添加了 C# 9 和代碼生成器之前的規則:
C#9 之后的規則:
部分方法可以有返回類型。
部分方法可以有參數。
部分方法可以具有訪問修飾符。
但是,如果他們這樣做,那么他們必須有一個實現。
https://www.codeproject.com/Articles/30101/Introduction-to-Partial-Methods
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.