8

Consider the following class written in c# .net 4.0 (typically found in a nhibernate class):

public class CandidateEntity : EntityBase
{
    public virtual IList<GradeEntity> Grades { get; set; }

    public CandidateEntity()
    {
         Grades = new List<GradeEntity>(); 
    }
}

This line gets a well founded warning "virtual member call in the constructor". Where shall I initialize this collection ?

Regards,

Calin
  • 6,661
  • 7
  • 49
  • 80
  • Duplicate? [Virtual member call in a constructor](http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor) – Tomas Jansson Jan 23 '11 at 19:50
  • 2
    @Tomas, not necessarily a duplicate as that question was more asking why it's bad to initialize a virtual member from a constructor. Good reading for OP none the less. – Vadim Jan 23 '11 at 19:55

4 Answers4

11

The backing field is one way. Another is to use a private setter. This works well in nHibernate.

public virtual IList<GradeEntity> Grades { get; private set; }

public CandidateEntity()
{
     Grades = new List<GradeEntity>();
}
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
9

Use a backing field and initialize the backing field in the constructor. Alternatively make the class sealed.

private IList<GradeEntity> _grades

public virtual IList<GradeEntity> Grades
{
   get { return _grades; }
   set { _grades = value; }
}

public CandidatesEntity()
{
   _grades = new List<GradeEntity>();
}
Vadim
  • 17,897
  • 4
  • 38
  • 62
  • So the answer on how to initialize a virtual member is to not make it virtual ?? – tenor Jan 23 '11 at 19:56
  • This makes sense, I wonder why it didn't occurred to me before. Thank you. – Calin Jan 23 '11 at 19:57
  • @tenor, Grades is still virtual and derived classes can override the implementation however they want. Read this http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor for a good explanation on why it's bad to initialize virtual members in a constructor – Vadim Jan 23 '11 at 19:59
0

If you make the class sealed you won't get the warning either (because the issue is only an issue if you inherit this class and override the member).

Edit after OP comment:

Ah, right. I usually encounter this only when I'm dealing with inherited virtual members. Yads' answer is probably the most useful for you.

Please also note you don't have to make the entire property virtual. Consider this:

List<Grade> Grades { 
     get { return _grades; }
     set { _grades = value; OnGradesChanged(); }

protected virtual OnGradesChanged()
{ }

Usually, you don't want to store the Grades in a different way in the derived class. You just need to do some updating when it changes. This way, you provide more guidance to the derived class, and you are sure that you can trust the backing field.

P.S. You are aware that people can edit the List<Grade> without your classes seeing it? You should consider using ObservableCollection which includes an event when the collection is changed externally. In that case, you only need to expose a readonly Grades property.

  • if i make the class sealed I can't have any virtual properties in it :( – Calin Jan 23 '11 at 19:58
  • Jan interesting suggestions. I think OP is using NHibernate or some kind of ORM framework which requires all members be virtual so while these suggestions are definitely useful in a lot of situations he's likely constrained by 3d party constraints. – Vadim Jan 23 '11 at 20:48
-1

Create an overridable (virtual) method called OnInit or something similar and initialize Grade in there, then call OnInit from the constructor.

The warning is there to inform you that you are creating a behavior that will be difficult for implementers to override.

tenor
  • 1,095
  • 6
  • 8
  • That's not true. The compiler is warning you about a potential real problem if this class is inherited. What you suggest only hides the problem from compile time static analysis. –  Jan 23 '11 at 19:58
  • Nope, what I suggest is giving implementers a chance to override the bad behavior the compiler is trying to warn you about. See http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor/119543#119543 – tenor Jan 23 '11 at 20:02
  • @jdv-Jan de Vaan. Never mind. You're right. I misunderstood *why* it's wrong to have a constructor call a virtual member. – tenor Jan 23 '11 at 20:10