Collection inheritance

Posts   
 
    
Deivis
User
Posts: 23
Joined: 22-Aug-2005
# Posted on: 04-Jul-2006 21:55:16   

In previous LLBLGen version we could write something like this:


public static void Main()
{
      CarCollection cars = new CarCollection();
      cars.GetMulti(null);
      SportsCarCollection sportsCars = new SportsCarCollection();
      cars.GetMulti(null);

      PrintBrandNames(cars);
      PrintBrandNames(sportsCars); // doesn't work in v2.0 anymore
}

public static void PrintBrandNames(CarCollection cars)
{
      foreach(CarEntity car in cars)
      {
            Console.WriteLine(car.BrandName);
      }
}

What are the ways to do this in v2.0? By the way this is a very simplified example - I would just create an overloaded method here, but I used the collection inheritance feature quite heavily in my code, so this is not a solution.

bclubb
User
Posts: 934
Joined: 12-Feb-2004
# Posted on: 05-Jul-2006 02:15:11   

public static void Main()
{
     CarCollection cars = new CarCollection();
     cars.GetMulti(null);
     SportsCarCollection sportsCars = new SportsCarCollection();
     cars.GetMulti(null); // This should be sportsCars.GetMulti(null);

     PrintBrandNames(cars);
     PrintBrandNames(sportsCars); // doesn't work in v2.0 anymore
}

public static void PrintBrandNames(CarCollection cars)
{
     foreach(CarEntity car in cars)
     {
            Console.WriteLine(car.BrandName);
     }
}

The second GetMulti call should be done using the sportsCars Collection. Let us know if that does not fix the situation.

Deivis
User
Posts: 23
Joined: 22-Aug-2005
# Posted on: 05-Jul-2006 06:35:56   

bclubb wrote:

The second GetMulti call should be done using the sportsCars Collection. Let us know if that does not fix the situation.

Sorry that was a typo. The problem still exists. The code should look like this:


public static void Main()
{
     CarCollection cars = new CarCollection();
     cars.GetMulti(null);
     SportsCarCollection sportsCars = new SportsCarCollection();
     sportsCars.GetMulti(null);

     PrintBrandNames(cars);
     PrintBrandNames(sportsCars); // doesn't work in v2.0 anymore
}

public static void PrintBrandNames(CarCollection cars)
{
     foreach(CarEntity car in cars)
     {
            Console.WriteLine(car.BrandName);
     }
}

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39928
Joined: 17-Aug-2003
# Posted on: 05-Jul-2006 11:31:26   

In .NET 2.0 generics are used. This gave the following problem: Say you have two classes: A and B, where B is a subtype of A. One would assume that: List<B> l = new List<B>(); would be castable to List<A> as B is a subtype of A, right? but that's not supported in C# nor VB.NET. It's called co-variance and although the CLR supports it, the two languages don't.

It's unfortunate as B[] b = new B[10]; can be casted to: A[] a = (A[])b;

so you would expect that co-variance is also true for generics, but that's not the case.

As selfservicing used strongly typed named collections like CustomerCollection, we couldn't simply drop these and migrate to EntityCollection<T>, as that would break so much code, upgrading would be too painful. So the strongly typed named collections were kept.

However, due to the problem with the absense of co-variance, it gave another problem:

public class EmployeeCollection : EntityCollectionBase<EmployeeEntity> { //... }

and: public class ManagerCollection : EmployeeCollection { }

would make the ManagerCollection be still typed as an Employee collection, which was of course not what you would want.

We toyed with various options, one being the fact that if a hierarchy was used, the supertype would use: public class EmployeeCollection : EntityCollectionBase<EntityBase>

and we would generate strongly typed methods into the collections which were typed to the type of entity owning the collection, for example the indexer, using the new / Shadows accessors, however that would give ugly code and it would basicly mess up a lot.

Another one was actually what we've chosen: every entity collection class derives from EntityCollectionBase<T> instead. It was the least troublesome solution we could come up with, keeping the code clean and also still using generics.

It's actually a paradigm shift: from inheritance to generics: when generics are used with a collection, inheritance is basicly over, as you would run into co-variance trouble, unless the generic describing type (T) is the same, which isn't the case in your situation.

Your static method PrintBrandNames should be rewritten as: public static void PrintBrandNames(IEntityCollection cars)

and it should work.

We know it's unfortunate, however with the named collections in selfservicing, we were between a rock and a hard place so any solution we would come up with wouldn't be ideal.

Frans Bouma | Lead developer LLBLGen Pro