2013-02-20 72 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

相關問題