We have a class that has a public property that is of type List<T>.
FXCop generates a DoNotExposeGene ricLists error, indicating
"System.Collect ions.Generic.Li st<Tis a generic collection designed
for performance not inheritance and, therefore, does not contain any
virtual members. The following generic collections are designed for
inheritance and should be exposed instead of
System.Collecti ons.Generic.Lis t<T>.
* System.Collecti ons.ObjectModel .Collection<T>
* System.Collecti ons.ObjectModel .ReadOnlyCollec tion<T>
* System.Collecti ons.ObjectModel .KeyedCollectio n<TKey, TItem"
Our property is not "virtual" and thus cannot be overridden. We used
List<Tbecasue we wanted a generic array. A collection is unordered
and thus not as good a match, even if it is better designed for
inheritance.
Can anyone explain in more depth why having a non-virtual, List<t>
property is bad? Why should I care is List<Thas any virtual members
when I am simply using an instance of and _not_ inheriting from
List<T>?
List<Tis intended to be a workhorse class used in implementation. By exposing
a List<Tin the interface of your class, you are breaking encapsulation
by giving client code access to an implementation detail of your class--especially
if your property provides direct access to the internal List<T>. For example,
this breaks encapsulation:
public class EmployeeCensus
{
private List<Employeem_ Employees;
public EmployeeCensus( IEnumerable<Emp loyeeemployees)
{
m_Employees = new List<Employee>( employees);
}
public List<EmployeeEm ployees { get { return m_Employees; } }
}
Any client code of the EmployeeCensus class could easily corrupt its state
by calling methods on the List<Employeeex posed by the Employees property.
And, if client code is responsible for maintaining the state of the EmployeeCensus
class, there's a design issue.
Proper encapsulation is to *not* expose the List<Tbut to expose a Collection<T>,
ReadOnlyCollect ion<Tor KeyedCollection <TKey, TItemlike this:
public class EmployeeCensus
{
private List<Employeem_ Employees;
public EmployeeCensus( IEnumerable<Emp loyeeemployees)
{
m_Employees = new List<Employee>( employees);
}
public ReadOnlyCollect ion<EmployeeEmp loyees { get { return m_Employees.AsR eadOnly();
} }
}
It's a shame that these classes were included in a different namespace (System.Collect ions.ObjectMode l)
because many developers haven't discovered them yet or realize that they
should be using them.
Best Regards,
Dustin Campbell
Developer Express Inc.