覆盖部分类中的虚拟方法

Posted

技术标签:

【中文标题】覆盖部分类中的虚拟方法【英文标题】:Override a virtual method in a partial class 【发布时间】:2013-06-18 22:22:10 【问题描述】:

我目前正在使用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)  //....

当我尝试编译此代码时出现错误:

Type 'Nop.Services.Orders.OrderProcessingService' 已经定义了一个 名为“PlaceOrder”的成员具有相同的参数类型

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

【问题讨论】:

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

您不能在同一个类上覆盖虚拟方法。部分类只是定义在不同位置拆分的同一个类,它没有定义层次结构,所以这是不可能的

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

你应该创建一个继承类来实现你的目标

public class MyOrderProcessingService : OrderProcessingService

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

【讨论】:

感谢克劳迪奥,我想这就是我正在寻找的答案,今天有点晚了! 你是如何解决这个@DenDave的,因为在 Nop 中这样做的目的是避免更改原始源代码。如果您必须修改原始的 Partial 类,它就会达到目的。【参考方案2】:

不完全清楚你想要什么,但也许你可以使用 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 关键字也是非法的。并且私有方法不允许是virtualpartial方法必须返回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 方法的课程结束。

【讨论】:

【参考方案3】:

你不能那样做。 partial 基本上所做的就是告诉 C# 编译器将这两段代码连接在一起。

一个 hacky 解决方案是完成该类,然后从该类继承并覆盖您想要的方法,例如这是一个简单的例子:

public partial class A

    public virtual void X()  

public partial class A

    public void Y()  

public class B : A

    public override void X()  

【讨论】:

【参考方案4】:

您可以使用分部类将一个类的代码拆分为多个,但您不能将单个方法拆分为两个分部类。你只需要在一个地方有方法。如果您想扩展功能,请寻找适合您场景的其他方法,例如子类化或组合等。

【讨论】:

但是,partial void 方法存在。【参考方案5】:

问题是从技术上讲,您仍然在同一个班级。部分类在编译时本质上是组合在一起的,所以它看到的是两个方法都定义在同一个类中。如果你使用子类,你可以这样做,但你不能在同一个类中定义两次方法。

【讨论】:

以上是关于覆盖部分类中的虚拟方法的主要内容,如果未能解决你的问题,请参考以下文章

用另一个部分类覆盖部分类的默认构造函数

部分类静态类Object类ToString()方法扩展方法的使用

如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext

怎样避免在EF自己主动生成的model中的DataAnnotation被覆盖掉

单元测试引用了关键部分类

如何实现基类的虚方法,并在c#中的覆盖方法中获取基方法实现[重复]