2013-02-20 83 views
5

我为我的C#项目使用NHibernate,因此我有几个模型类。在C#中调用虚拟方法的替代方法

让我们假设下面的例子:

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. 

This page还介绍了为什么这是错的,我也理解。但我不知道如何解决这个问题。

当我删除所有构造函数,并添加下面的方法...

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

     } 

....设置数据后,我打电话的标准构造becaue NHibernate的初始化失败,我不能启动我的aplication。它说:

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' 

但这种方法设置虚拟将是相同的错误,当我只设置在构造虚拟成员。 如何避免这些错误(侵犯)?

+0

为什么不将值设置为字段而不是属性在构造? – 2013-02-20 14:27:32

+0

@voroninp你无法轻松访问NHibernate的字段 – Andrey 2013-02-20 14:29:39

+0

因为我的模型实际上有大约10个成员,所以我创建了新的房间对象qiet iften。我不想单独设置每个属性。 – Metalhead89 2013-02-20 14:29:43

回答

4

问题在于虚拟集。将值传递给基类构造函数中的虚拟属性将使用覆盖集而不是基本集。如果overriden设置依赖于派生类中的数据,那么您遇到了麻烦,因为派生类的构造函数尚未完成。

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

如果可能,请尝试为每个属性创建支持字段,并在基类构造器中使用它们。

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

1

我希望以下工作之一:

  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; 
    } 
} 
+0

NHibernate不支持非虚拟属性。 我也不能设置创建方法静态,因为那么属性也必须是静态的,这不是我想要的(我也不确定这是否会奏效) – Metalhead89 2013-02-20 15:08:42

+0

我编辑了我的帖子以阐明选项3.'Create'方法是静态的,但属性不是。 – 2013-02-20 18:29:01

+0

如果您使构造函数受保护,选项3更有意义,因此构造'Room'实例的唯一方法是使用静态方法。 – 2016-01-04 15:11:24

相关问题