2013-04-17 14 views
18

Większość (jeśli nie wszystkie) moje jednostki POCO mają strukturę wirtualną. Potrzebuję tych funkcji, aby były wirtualne, tak aby obiekty mogły być obciążone.Jak uniknąć wywoływania funkcji wirtualnej w konstruktorze?

Jeśli zainicjuję Accommodations w konstruktorze, będę wywoływał funkcję wirtualną w konstruktorze, co jest złą praktyką.

Ale jak mogę zainicjować Accommodations, jeśli nie w konstruktorze?

public class Venue 
{ 
    public Venue() 
    { 
     Accommodations = new HashSet<Accommodation>(); 
    } 

    public virtual ICollection<Accommodation> Accommodations { get; set; } 
} 
+1

punkt leniwy załadunku jest _nie_ aby go zainicjować w ogóle, dopóki pierwsze użycie. –

+0

@JohnWillemse Jeśli pozwolę mu null, otrzymam wyjątek null w mojej opinii. –

+0

Nie, testujesz na wartość zerową i inicjalizujesz ją w razie potrzeby. Zobacz poniżej odpowiedź Willema Duncana na demonstrację użycia. Być może my mylimy różne wzory tutaj, zgodnie z komentarzem Daniela dotyczącym tej samej odpowiedzi. –

Odpowiedz

12
public class Venue 
{ 
    private accommodations_ = new HashSet<Accommodation>(); 

    public Venue() { } 

    public virtual ICollection<Accommodation> Accommodations 
    { 
     get { return accommodations_; } 
     set { accommodations_ = value; } 
    } 
} 
+3

Co to za dziwna konwencja nazewnicza? Zwykle umieszczasz podkreślnik z przodu. –

+1

@DanielHilgarth, nie nazwałbym tego w ogóle konwencją - tylko mój (prawdopodobnie zły) nawyk, który naprawdę muszę zmienić;) –

+0

EF nie bardzo lubi prowadzić podkreślenia. – Casey

2

Z leniwy załadunku, nawet nie zainicjować Accommodations aż to pierwsze dostępne, więc zostaw go null.

Można owinąć w następujący sposób, aby automatycznie inicjować się:

private ICollection<Accommodation> _accommodations; 

public virtual ICollection<Accommodation> Accommodations { 
    get { 
     if (_accommodations == null) 
     { 
      // Initialize or load data here. 
      _accommodations = new HashSet<Accommodation>(); 
     } 
     return _accomodations; 
    } 
    set { 
     _accommodations = value; 
    } 
} 

Pamiętaj, aby przeczytać komentarz poniżej dotyczące tego rozwiązania!

+7

Mówi o leniwym ładowaniu w kontekście ORM. ORM zatroszczy się o to wszystko, więc twoja odpowiedź nie trafia w sedno. Ponadto zapoznaj się z [tą odpowiedzią] (http://stackoverflow.com/questions/14774008/good-or-bad-practice-initializing-objects-in-getter/14774042#14774042) na temat praktyki, którą tu pokazujesz. –

+0

Dobra rada, ucz się czegoś każdego dnia, dodałeś wskaźnik do odpowiedzi. –

+0

Dzięki za link Daniel. –

14

Inną opcją jest, aby zaznaczyć setter jako prywatne. To wyeliminuje problem wywoływania wirtualnych członków w konstruktorze.

Po wykonaniu tej czynności należy określić sposoby dzwonienia (inne niż EF), aby ustawić tę właściwość zgodnie z wymaganiami projektu. Możesz użyć przeciążonego konstruktora, aby przekazać listę obiektów zakwaterowania lub opcjonalnie enkapsulować swoją kolekcję (projekt oparty na domenie) i użyć metod dodawania/usuwania elementów (uwaga, z EF to staje się "hackish", ponieważ brakuje obsługi dla w pełni zamkniętego zbiory, w przeciwieństwie do NHibernate):

public class Venue 
{ 
    public Venue() 
    { 
     Accommodations = new HashSet<Accommodation>(); 
    } 

    public Venue(ICollection<Accommodation> accommodations) 
    { 
     Accommodations = new List<Accommodation>(accommodations); 
    } 

    public virtual ICollection<Accommodation> Accommodations { get; private set; } 
} 
+2

Dokładnie to, czego potrzebowałem. Zabawne, jak to pytanie ma ponad rok, a mimo to publikujesz tę odpowiedź zaledwie 4 godziny, zanim pójdę jej szukać! – Xcelled194

0

przy domyślnym inicjalizacji C# 6.0 to może być uproszczone bez użycia zmiennych prywatnych:

public class Venue 
{ 
    public virtual ICollection<Accommodation> Accommodations {get; set; } = new HashSet<Accommodation>(); 
} 
Powiązane problemy