在部分类中覆盖虚方法

13

我目前正在使用nopCommerce源代码,尽最大努力避免直接编辑源代码,而是使用与源代码分离的部分类和插件来实现更改,以便在需要升级版本时进行。

我想通过在同一程序集中使用部分类来对下订单的代码进行一些更改:

原始源代码:

namespace Nop.Services.Orders {

  public partial class OrderProcessingService : IOrderProcessingService {

        public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentRequest)
        { //....

我的部分类:

namespace Nop.Services.Orders {

  public partial class OrderProcessingService : IOrderProcessingService {

    public override PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentRequest) { //....

当我尝试编译此代码时,会出现以下错误:

类型“Nop.Services.Orders.OrderProcessingService”已经定义了一个与参数类型相同的成员“PlaceOrder”

但是我正在使用override,原始类中的方法是virtual的,有人能告诉我我在哪里做错了吗?如何覆盖这个方法?


overridevirtual用于继承,而partial类不被视为继承。 - Matthew
有没有其他方法可以覆盖该方法?我认为nopCommerce在任何地方都使用部分类是为了能够进行扩展而不必更改源代码。 - DevDave
2
通常情况下,partial 类与自动生成的代码一起使用。为了 override 方法 PlaceOrder,您需要创建一个继承 OrderProcessingService 的类。 - Matthew
要在Nop.Commerce中“正确”地完成此操作,您需要在插件中提供自己的IOrderProcessingService实现,其中您可能会从原始服务继承并覆盖所需的方法。当您想要更改前端行为时,事情变得更加复杂。您可以使用部分类和小部件插件扩展一些模型和控制器,但更改现有控制器的行为会迫使您更改原始代码。也许新版本有更好的方法来实现这一点。 - jahu
5个回答

14

在同一个类上无法覆盖虚方法。部分类只是将定义分割在不同位置的同一类,它不定义层次结构,因此这是不可能的。

可以将类、结构或接口的定义拆分到两个或多个源文件中。每个源文件都包含类定义的一个部分,在应用程序编译时将所有部分组合起来。

您应该创建一个继承类以实现您的目标。

public class MyOrderProcessingService : OrderProcessingService
{
    public override PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentRequest) { //....
}

谢谢Claudio,这就是我在寻找的答案,我想现在有点晚了! - DevDave
你是怎样解决的,@DenDave?在Nop中的目标是避免更改原始源代码。如果您不得不修改原始部分类,那么这有点背道而驰。 - rollsch

10

不是很清楚你想要什么,但也许你可以使用partial 方法

因此,负责类的第一部分的“一方”可以单独在以下位置签名:

“原始源代码”:

namespace Nop.Services.Orders {

  public partial class OrderProcessingService : IOrderProcessingService {

    partial void PlaceOrder(ProcessPaymentRequest processPaymentRequest,
      ref PlaceOrderResult result);

接下来,负责另一个“部分”的“一方”可能会选择提供方法的实现。如果他们提供了一个实现,那么它看起来会像这样:

“我的部分类”:

namespace Nop.Services.Orders {

  public partial class OrderProcessingService : IOrderProcessingService {

    partial void PlaceOrder(ProcessPaymentRequest processPaymentRequest,
      ref PlaceOrderResult result) {

      // actual code goes here
    }

需要注意以下几点:

  • partial 方法不能是 public 的,必须是 private 的,而且甚至指定 private 关键字都是不合法的。而且私有方法不允许是 virtual 的。
  • partial 方法必须返回 void,参数中不能有被标记为 out 的参数,所以我们将 result 作为 ref 参数。
  • 第一个“部分”的声明中有一个分号 ; 而不是方法体。
  • 如果存在其他“部分”中的实现,则其具有方法体 { ... }

现在在“原始源代码”中可以像这样调用该方法:

// ...
PlaceOrderResult result = null;
PlaceOrder(someRequest, ref result);
// check if 'result' was changed to something non-null, and if so use 'result'

注意:
如果类的任何“部分”都没有选择实现 PlaceOrder,则在编译之前,该方法(包括所有对它的调用!)将被(心理上)从类的所有部分中删除。这也会删除调用中参数的求值,如果该求值具有副作用(例如PlaceOrder(FindRequestAndCauseOtherEffects(), ref result);),则可能很重要。
我之前提到的方法必须返回void并且没有out参数的限制可以被理解为其结果。
今天关于partial void方法的课程结束了。

4

你不能这么做。 partial 的基本作用是告诉C#编译器将两个代码段连接在一起。

一个有点欺骗性的解决方案是完成该类,然后从中继承并覆盖您想要的方法,例如下面是一个简单的示例:

public partial class A
{
    public virtual void X() { }
}
public partial class A
{
    public void Y() { }
}
public class B : A
{
    public override void X() { }
}

3
您可以使用部分类来将一个类的代码分成多个部分,但是您不能将单个方法拆分为2个部分类。您需要将方法放在一个地方。如果您想扩展功能,则可以寻找其他方法,如子类化或组合等,以适应您的情况。

然而,存在着“partial void”方法。 - Jeppe Stig Nielsen

2

问题在于你仍然在同一个类中。部分类在编译时本质上是合并的,因此它看到的是在同一个类中定义的两个方法。如果你使用了子类,那么可以这样做,但是你不能在同一个类中定义两次该方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接