在C#中调用虚拟方法的替代方法

本文关键字:方法 虚拟 调用 | 更新日期: 2023-09-27 18:00:13

我的C#项目使用NHibernate,因此我有几个模型类。

假设以下示例:

using System;
namespace TestProject.Model
{
    public class Room
    {
        public virtual int Id { get; set; }
        public virtual string UniqueID { get; set; }
        public virtual int RoomID { get; set; }
        public virtual float Area { get; set; }
    }
}

到目前为止,用NHibernate映射这些对象效果良好。现在我想生成一个新的Room对象,并将其存储在数据库中。为了避免单独设置每个成员,我在模型类中添加了一个新的构造函数。下面的虚拟成员我写:

public RoomProperty()
{
}

public RoomProperty(int pRoomId, int pArea)
{
        UniqueID = Guid.NewGuid().ToString();
        RoomID = pRoomId;
        Area = pArea;
}

使用FxCop分析我的代码告诉我以下内容:

"ConstructorShouldNotCallVirtualMethodsRule"
This rule warns the developer if any virtual methods are called in the constructor of a non-sealed type. The problem is that if a derived class overrides the method then that method will be called before the derived constructor has had a chance to run. This makes the code quite fragile. 

这一页也描述了为什么这是错误的,我也理解。但我不知道如何解决问题。

当我擦除所有构造函数并添加以下方法时。。。

public void SetRoomPropertyData(int pRoomId, int pArea)
        {
            UniqueID = Guid.NewGuid().ToString();
            RoomID = pRoomId;
            Area = pArea;
        }

为了在我调用标准构造函数后设置数据,我无法启动应用程序,因为NHibernate无法初始化。上面写着:

NHibernate.InvalidProxyTypeException: The following types may not be used as proxies:
VITRIcadHelper.Model.RoomProperty: method SetRoomPropertyData should be 'public/protected virtual' or 'protected internal virtual'

但是,将此方法设置为virtual将是与我刚刚在构造函数中设置虚拟成员时相同的错误。如何避免这些错误(违规)?

在C#中调用虚拟方法的替代方法

问题在于虚拟集。将值传递给基类构造函数中的虚拟属性将使用overriden-set而不是base-set。若覆盖集依赖于派生类中的数据,那个么您就有麻烦了,因为派生类的构造函数还并没有完成。

如果您绝对确定,任何子类都不会在覆盖集中使用其状态的任何数据,那么您可以在基类构造函数中初始化虚拟属性。考虑在文档中添加适当的警告。

如果可能的话,尝试为每个属性创建后备字段,并在基类构造函数中使用它们。

也可以将属性初始化推迟到派生类。要实现这一点,请在派生类的构造函数中调用的基类中创建一个初始化方法。

我希望以下其中一项能够工作:

  1. 使属性非虚拟(只要NHibernate支持,则首选)
  2. 从自动实现的属性更改为具有显式支持字段的属性,并在构造函数中设置字段,而不是设置属性
  3. 创建一个静态Create方法,该方法首先构造对象,然后在返回构造的对象之前为属性设置值

编辑:从评论中我看到选项#3不清楚。

public class Room
{
    public virtual int Id { get; set; }
    public virtual string UniqueID { get; set; }
    public virtual int RoomID { get; set; }
    public virtual float Area { get; set; }
    public static Room Create(int roomId, int area)
    {
        Room room = new Room();
        room.UniqueID = Guid.NewGuid().ToString();
        room.RoomID = roomId;
        room.Area = area;
        return room;
    }
}

IMHO,好主意是使基类抽象及其构造函数受到保护。接下来,继承的类有其构造函数private和-对于外部世界-统一的静态方法,如"实例",它首先初始化构造函数,然后-按正确顺序调用整个类方法集,最后-返回类的Instance