2013-02-20 18 views
5

Używam NHibernate dla moich obiektów C# i dlatego mam kilka klas modeli.Alternatywa dla wywoływania wirtualnej metody w C#

Załóżmy następujący przykład:

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

    } 
} 

mapowanie tych obiektów z NHibernate działa dobrze do tej pory. Teraz chcę wygenerować nowy obiekt Room i chcę go zapisać w bazie danych. Aby uniknąć ustawiania każdego członka osobno, dodaję nowy konstruktor do klasy modelu. Poniżej wirtualnych członków piszę:

public RoomProperty() 
{ 

} 


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

Analizując mojego kodu z FxCop mówi mi, co następuje:

"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 opisuje również, dlaczego to jest złe i ja także zrozumieć. Ale nie jestem pewien, jak rozwiązać problem.

Kiedy usunięcie wszystkich konstruktorów i dodaj następujący sposób ...

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

     } 

.... ustawić dane po zadzwoniłem średnia konstruktor nie mogę rozpocząć mój Aplikacja becaue NHibernate nie inicjalizacji. Mówi:

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' 

ale ustawienie tej metody do wirtualnego byłby taki sam błąd jak wtedy, gdy po prostu ustawić wirtualnych członków w konstruktorze. Jak mogę uniknąć tych błędów (naruszeń)?

+0

dlaczego nie ustawić wartości w polach nie właściwości na budowie? –

+0

@voroninp nie można uzyskać dostępu do pól, które można łatwo z NHibernate – Andrey

+0

Ponieważ mój model faktycznie ma około 10 członków i tworzę nowe obiekty pokojowe qiet iften. Nie chcę osobno ustawić każdej własności. – Metalhead89

Odpowiedz

4

Problem dotyczy zestawu wirtualnego. Przekazanie wartości do właściwości wirtualnej w konstruktorze klasy podstawowej spowoduje użycie zestawu overriden zamiast zestawu podstawowego. Jeśli zestaw overriden opiera się na danych w klasie pochodnej, masz kłopoty, ponieważ konstruktor klasy pochodnej jeszcze nie został wykonany.

Jeśli jesteś absolutnie pewny, że jakakolwiek podklasa nie użyje żadnych danych ze swojego stanu w zmienionym zestawie, możesz zainicjować właściwości wirtualne w konstruktorze klasy podstawowej. Rozważ dodanie odpowiedniego ostrzeżenia do dokumentacji.

Jeśli to możliwe, spróbuj utworzyć pola kopii dla każdej właściwości i użyj ich w contructor klasy podstawowej.

Możesz również odłożyć inicjalizację właściwości do klasy pochodnej. Aby to osiągnąć, utwórz metodę inicjującą w klasie bazowej, którą wywołasz w konstruktorze klasy pochodnej.

1

się spodziewać jedną z następujących czynności pracy:

  1. sprawiają, że właściwości nie wirtualna (korzystna, o ile umożliwia to NHibernate).
  2. Zmiana z właściwości zaimplementowanych automatycznie na właściwości za pomocą jawnego pola kopii i ustawienie pól w konstruktorze zamiast ustawiania właściwości.
  3. Utwórz statyczną metodę Create, która najpierw tworzy obiekt, a następnie ustawia wartości do właściwości przed zwróceniem skonstruowanego obiektu.

Edytuj: Z komentarza widzę opcję nr 3 nie było jasne.

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 nie obsługuje właściwości innych niż wirtualne. Nie mogę również ustawić metody create static, ponieważ wtedy również właściwości muszą być statyczne, co nie jest tym, czego chcę (nie jestem też pewien, czy to zadziała) – Metalhead89

+0

Edytowałem swój post, aby wyjaśnić opcję 3. "Create" Metoda jest statyczna, ale jej właściwości nie są. –

+0

Opcja 3 ma więcej sensu, jeśli uczynisz konstruktora chronionym, więc jedynym sposobem na skonstruowanie instancji 'Room' jest metoda statyczna. –

Powiązane problemy