我知道部分方法可以用于将方法的定义拆分到多个文件中。但是我想知道,如果每个文件中都包含代码,这样做是否允许?
例如,假设我有一个方法 private partial void Foo()
。我在文件A和文件B中都定义了它。两个实例中是否都可以包含该方法的代码,还是只能选其中一个?如果允许两个都包含代码,那我会感到惊讶。
我知道部分方法可以用于将方法的定义拆分到多个文件中。但是我想知道,如果每个文件中都包含代码,这样做是否允许?
例如,假设我有一个方法 private partial void Foo()
。我在文件A和文件B中都定义了它。两个实例中是否都可以包含该方法的代码,还是只能选其中一个?如果允许两个都包含代码,那我会感到惊讶。
不行,你不能这样做。如果可以的话,当你调用Foo()
时,哪个代码会先执行呢?如果两个版本都在处理(并修改)全局状态,那么知道执行顺序就非常重要。
无论如何,这是没有意义的。所以不行,你不能这样做。
##恶劣示例1 作为这种可能性出现的潜在恶劣行为的一个简单示例,假设你可以这样做,并且假设你有以下代码:
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 bool HasRealSolution(double a, double b, double c) {
return false;
}
}
现在,我们该如何理解这段代码呢?在调用HasRealSolution(1, 2, 1)
后,应该考虑哪个返回值呢?一个方法怎么可能有两个不同的、同时存在的返回值*?我们可不是在处理非确定有限状态自动机!
对于那些认为在这个假设的世界中我的不存在的部分方法应该是void
的人,请将return
替换为将某个私有字段设置为该类的值。效果几乎相同。
*请注意,我所说的不是由两个值组成的单个返回值,比如Tuple<T1, T2>。我说的是两个返回值。(???)
partial
方法必须是void
。 - Mehrdad Afshari这实际上是对@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# 3.0 规范的有效代码,但输出可能会是:
x: 42; y: 84
或者x: 84; y: 42
编译器可以生成其中任意一个,甚至不会发出警告。
C#语言要求partial方法返回void类型。partial方法的签名最多只能定义一次。同样地,实现也应该最多定义一次。
partial
应该保留用于代码生成。如果确实需要将单个类中的内容分离到多个文件中,那么这个类可能太大了,应该拆分成多个类。 - Mehrdad Afshari不行。只能在一个部分类中实现一次有代码的部分方法。如果定义多个带有实现的部分方法,则会导致编译器错误。
partial
方法实例也是错误的。最多只能存在一个声明和一个实现。 - Mehrdad Afshari/// <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>
静态部分方法 IsTheTypeSerializable(Type type, ref Boolean serializable);
该方法可用于实现包含多个选项的类型序列化框架,具体取决于混合了哪些部分类以及包含了哪些序列化程序。即使只有单个实现(根据编译器规则所能存在的全部),实现也必须按照上述方法文档中描述的逻辑进行,因为无法保证在定义部分中的哪个时间点调用该方法。如果允许多个实现,则整体逻辑必须保证结果不会依赖于实现调用的顺序。
在我们的框架中,我们实际上使用可加载的委托来执行不同情形下的可序列化性分析。然而,对于这种情况确实允许多个实现将是方便的。
我们推测 Microsoft 害怕新手开发人员使用这个危险特性会导致混乱。使用此功能需要知道自己在做什么。
这是不可能的。你在一个地方定义签名,在另一个地方实现。
详情请参见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之后的规则:
分部方法可以有返回类型。
分部方法可以有out参数。
分部方法可以具有访问修饰符。
然而,如果有访问修饰符,则必须有实现。
https://www.codeproject.com/Articles/30101/Introduction-to-Partial-Methods