拆分/组合部分方法

时间:2010-01-18 18:29:50

标签: c#

我理解可以使用部分方法在多个文件中拆分方法的定义。我很好奇,如果允许跨多个文件的方法的每个定义包含代码?

例如,假设我有方法private partial void Foo()。假设我已经在文件A和文件B中定义了它。两个实例都可以包含方法中的代码,还是只包含其中一个?如果允许,我想我会感到惊讶。

7 个答案:

答案 0 :(得分:21)

这是对@ 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#规范v3.0,这是有效的C#,但输出可以是:

x: 42; y: 84

x: 84; y: 42

允许编译器生成其中任何一个。它甚至不会产生警告。

C#语言需要部分方法才能获得void返回类型。部分方法签名最多可以定义一次。同样,实施应该最多定义一次。

答案 1 :(得分:19)

不,你不能。如果可以,当您致电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()时,它会打印什么价值?没意思!

令人讨厌的例子2

现在又是一个奇怪的问题。如何处理参数?并返回值?

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个不同的,同时的返回值 * ?我们没有处理nondeterministic finite automata

对于那些在这个假设世界中强加的人,我不存在的部分方法应该是void,将return s替换为在该类的某个私有字段上设置值。效果几乎相同。

* 请注意,我在这里所说的不是由两个值组成的单个返回值,例如元组。我在这里谈论两个返回值。 (???)

答案 2 :(得分:8)

没有。只有单个版本的部分方法可能包含代码。使用实现定义部分方法的多个实现将导致编译器错误。

答案 3 :(得分:5)

不,这是不可能的。此外,你有一点误会。部分方法的目的不是“跨多个文件拆分方法的定义”。

相反,partial method旨在将类的定义分割为多个文件。这很有用,特别是对于自动生成的代码,因为它允许您定义可自由实现的“可选”方法,但也可以自由忽略。

答案 4 :(得分:4)

正如其中一位响应者所指出的那样,在部分类的多个部分中排除多个部分方法实现没有技术原因。它现在很流行,即使根据Microsoft DOC来创建将在Silverlight中运行的程序集,也可以在完整的CLR下运行,具体取决于所包含的文件。 Microsoft自己的示例包括Silverlight兼容文件中的部分方法定义,其实现包含在将包含在CLR版本中的其他文件中。

当然,如果允许多个实现,开发人员必须意识到调用顺序是非确定性的。一个例子是一个方法,它采用一个bool的单一引用,表明当前环境能够做“某事”。

一个例子:

/// <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);

此方法可用于实现包含多个类型序列化选项的框架,具体取决于混合的部分类的哪些部分以及包含的序列化程序。即使只有一个实现(在编译器规则下也可以存在),实现必须遵循上面方法DOC中描述的逻辑,因为不能保证定义部分中的哪个点将是方法调用。如果允许多个实现,则整体逻辑必须保证结果不依赖于实现的调用顺序。

在我们的框架中,我们实际上使用可加载的委托来执行不同场景的可序列化分析。但是,确实可以方便地实现这种情况的多个实现。

我们猜测微软担心如果新手开发人员变得松散使用这个危险的功能会导致混乱。人们需要知道这样的事情是什么。

答案 5 :(得分:3)

这是不可能的。您可以在一个位置定义签名,并在另一个位置定义实现。

有关详细信息,请参阅MSDN

答案 6 :(得分:0)

您无法合并方法,但可以使用“部分方法”设置链。如果您想避免代码编织,这是一个选项。我不是说这是一个很好的选择,但它是一个选择。

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);
    }
}
  • 部分方法由partial修饰符指示。
  • 部分方法必须是私密的。
  • 部分方法必须返回void。
  • 部分方法只能在部分类中声明。
  • 部分方法并不总是有实现。
  • 部分方法可以是静态的和通用的。
  • 部分方法可以包含参数,包括ref但不能。
  • 您不能委托部分方法。

规则来自:

https://www.codeproject.com/Articles/30101/Introduction-to-Partial-Methods