Density Correction (or Generic Polymorphism Whaaaa?)

Density Correction (or Generic Polymorphism Whaaaa?)

Old forum URL: forums.lhotka.net/forums/t/552.aspx


tpancoast posted on Thursday, July 06, 2006

I don't get it.  I am new to CSLA.  I bought and read the 1.0 book a while ago, but now that we might actually use it, 2.0 is out.  I don't have the new book, so I am winging it.  I am also fairly new to .Net.  I am a Delphi coder and I have been dabbling in C#, but we are approaching real work now.
 
I am working on a proof of concept project to use the CSLA as the middle tier between our application and a content management system.  In that content management system you define different content types as classes.  Those classes can inherit from each other, but there are only properties; there is no behavior associated with a content class.  One of the designs I am considering (and therefor proving in the proof of concept) is to implement a simple CSLA class for each Content Class and mirroring the inheritance.
 
I have a Folder : BusinessBase that contains a Documents : BusinessListBase collection of Document : BusinessBase objects.  The individual objects in the Documents collection could be of the base Document class or it could be a Loan Document or a Batch Document or a Legal Document.
 
My confusion comes from your article: http://www.lhotka.net/Articles.aspx?id=b8515cd9-7f8e-43df-9efd-cd958dfdc21a
 
After reading that, I went and read about how Generics are not Polymorphic and I think I understand that pretty well.  The problem is that I don't see how that applies to the CSLA.  Sure BusinessBase is generic, but my Document class that I derive from it is a concrete class.

public class Document : BusinessBase<Document>

public class Documents : BusinessListBase<Documents, Document>

I should be able to derive classes from Document and the Documents collection should be able to contain them all.  I say should, but my shell application is working fine.  I have no problem using a cast to access an item in the list as a LoanDocument class.  The problem is, this is only a shell.  I don't have any DataPortal code at this time.  Is the problem related to serialization or with the Data Portal?
 
Can someone please tell me more about the problems I might have continuing down this road?  I must be missing something.

ajj3085 replied on Thursday, July 06, 2006

Well, one problem is that any class derived from Document would return Document from the Save method, not my MySubClassedDocument, which is what you'd expect.  There are other problems as well, if you search this forum you'll come across threads detailing them more.

skagen00 replied on Thursday, July 06, 2006

I am working through some of this same issue. I've stripped polymorphic behavior out of my classes for now and hope to revisit the subject at some point.

One problem that I ran into was the implementation of the collection class for polymorphic child objects - outlined here in Rocky's article that you mentioned:

http://www.lhotka.net/Articles.aspx?id=b8515cd9-7f8e-43df-9efd-cd958dfdc21a

Recently, after trying to work through this, I ran into a problem with implementing the data access methods as talked about in his article, outlined here (last post in the thread):

http://forums.lhotka.net/forums/thread/1285.aspx

Having shelved my pursuit of this for the moment, one avenue I have been giving real consideration to and have done a really cursory glance at is to bypass BusinessBase<T> and inherit right from Core.BusinessBase if I really really want inheritance with polymorphism. There is really not a lot in BusinessBase<T> that would have to be implemented, and it seems that BusinessListBase<T,C> works with C where C is IEditableBusinessObject, which is implemented by Core.BusinessBase. 

In my case, there are "Contacts" in the system - some of which are Individuals and some of which are Organizations. Using BusinessBase<T>, my Contact abstract class (which has a good deal of common implementation) needs to be generic <T> simply to pass along the type to BusinessBase<T>. Otherwise it really doesn't serve much purpose. Bypassing BusinessBase<T> allows Contact to be a non-generic abstract class.  I haven't really looked deeply into the ramifications and I don't really like breaking away from BusinessBase<T> as staying true to the framework is certainly important.

Of course, using BusinessBase<T> I end up with Contact<Individual> and Contact<Organization>, which are simply not the same class. They may indeed implement IContact, but as mentioned above I ran into some problems trying to implement Rocky's solution in his article and I decided to shelve it until I got some more "real work" done.

 

ajj3085 replied on Thursday, July 06, 2006

Sounds like a viable option if you don't need the functionality that BusinessBase<T> provides.

I'm not clear on why some of that functionality is there; the Clone and Data Access regions make sense there, but why isn't GetIdValue and the other functionality in Core.BusinessBase?  It doesn't seem like it would change anything moving those to Core.BusinessBase.

Andy

RockfordLhotka replied on Friday, July 07, 2006

skagen00:

Having shelved my pursuit of this for the moment, one avenue I have been giving real consideration to and have done a really cursory glance at is to bypass BusinessBase<T> and inherit right from Core.BusinessBase if I really really want inheritance with polymorphism. There is really not a lot in BusinessBase<T> that would have to be implemented, and it seems that BusinessListBase<T,C> works with C where C is IEditableBusinessObject, which is implemented by Core.BusinessBase. 

This is, in fact, the only reason Core.BusinessBase still exists. During the book review process it was suggested that Core.BusinessBase could go away - which is absolutely true. But I kept it specifically because you can create a NON-GENERIC version of BusinessBase by inheriting from Core.BusinessBase.

I would NOT have your business objects inherit directly from Core.BusinessBase - that is not a design for which Core.BusinessBase is intended. However, what you can do is create your own BusinessBase that inherits from Core.BusinessBase and then have your business objects inherit from that new base class.

This new BusinessBase class should (at a minimum) implement a Save() method - obviously returning type Object rather than a strong type, and GetIdValue(). You may also want to implement the protected DataPortal_XYZ methods.

I originally had just such a class in the framework, but dropped it in favor of only supporting BusinessBase<T>. I still think that was the right choice, because it reduced my surface area for testing and for the book (as it would have taken pages to explain the non-generic version, and then to show how to use it within ProjectTracker, etc.)  Still, in anticipation that someone would want to avoid all the complexity of generics, I did keep Core.BusinessBase so you could easily create a non-generic BusinessBase if that was useful.

All that said, in most cases you should be able to use IEditableBusinessObject to achieve polymorphic results without giving up the benefits of BusinessBase<T>.

tpancoast replied on Friday, July 07, 2006

O.K.  I am still reading some of the older messages in the forums, but this message confuses me again.  My understanding is that you can create a non-generic (concrete) version of BusinessBase simply by inheriting from BusinessBase and specifying its type parameter without specifying any new type parameters for the new class.  There shouldn't be any need to go back to Core.BusinessBase.  For example, this creates a new non-generic (concrete) class.
 
   public class MyClass : BusinessBase<MyClass>
 
Now that MyClass is concrete, you can inherit additional classes from it without any limitation on polymorphism.  In addition, as far as I know, generics support polymorphism, provided you are morphing from a generic type to a derived concrete type.  For example, take this snippit:
 
    public class BusinessBase<T>
    {
      virtual public string foo() { return("BusinessBase"); }
    }
 
    public class ConcreteBase : BusinessBase<ConcreteBase>
    {
      override public string foo() { return ("ConcreteBase"); }
    }
 
    public class ConcreteChild : ConcreteBase
    {
      override public string foo() { return ("ConcreteChild"); }
    }
 
    static void Main(string[] args)
    {
      List<ConcreteBase> concreteList = new List<ConcreteBase>();
      concreteList.Add(new ConcreteBase());
      concreteList.Add(new ConcreteChild());
      foreach (ConcreteBase item in concreteList)
        Console.Out.WriteLine(item.foo());
 
      List<BusinessBase<ConcreteBase>> genericList = new List<BusinessBase<ConcreteBase>>();
      genericList.Add(new BusinessBase<ConcreteBase>());
      genericList.Add(new ConcreteBase());
      genericList.Add(new ConcreteChild());
      // genericList.Add(new BusinessBase<ConcreteChild>()); // Compile Error:
      // Hit the limit of generic type polymorphism
      foreach (BusinessBase<ConcreteBase> item in genericList)
        Console.Out.WriteLine(item.foo());
 
      Console.In.ReadLine();
    }
ConcreteBase and ConcreteChild support polymorphism fine.  You don't run into a problem until you expect the compiler to understand that BusinessBase<ConcreteChild> is a child type of BusinessBase<ConcreteBase>.
 
This generic type to generic type comparison issue is the only limitation to polymorphism that I know of.  Is there something else?

RockfordLhotka replied on Saturday, July 08, 2006

Sure, that will work just fine as well.
 
Rocky


From: tpancoast [mailto:cslanet@lhotka.net]
Sent: Friday, July 07, 2006 5:35 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Density Correction (or Generic Polymorphism Whaaaa?)

O.K.  I am still reading some of the older messages in the forums, but this message confuses me again.  My understanding is that you can create a non-generic (concrete) version of BusinessBase simply by inheriting from BusinessBase and specifying its type parameter without specifying any new type parameters for the new class.  There shouldn't be any need to go back to Core.BusinessBase.  For example, this creates a new non-generic (concrete) class.

skagen00 replied on Monday, July 10, 2006

RockfordLhotka:

skagen00:

Having shelved my pursuit of this for the moment, one avenue I have been giving real consideration to and have done a really cursory glance at is to bypass BusinessBase<T> and inherit right from Core.BusinessBase if I really really want inheritance with polymorphism. There is really not a lot in BusinessBase<T> that would have to be implemented, and it seems that BusinessListBase<T,C> works with C where C is IEditableBusinessObject, which is implemented by Core.BusinessBase. 

This is, in fact, the only reason Core.BusinessBase still exists. During the book review process it was suggested that Core.BusinessBase could go away - which is absolutely true. But I kept it specifically because you can create a NON-GENERIC version of BusinessBase by inheriting from Core.BusinessBase.

I wonder why read-only objects didn't take this approach? I notice that the only reason (unless I'm missing something) ReadOnlyBase is generic is to strongly type the Clone method for the ICloneable interface. I wonder in some ways if there is a point at which it's good not to introduce generics.

Correction: I missed that Equals also is implemented with T considered.

 

tpancoast replied on Thursday, July 06, 2006

ajj3085:
Well, one problem is that any class derived from Document would return Document from the Save method, not my MySubClassedDocument, which is what you'd expect.  There are other problems as well, if you search this forum you'll come across threads detailing them more.
That is exactly what I would expect.  Sure, it returns the base Document type, but the actual class is of the derived LoanDocument type.  A call to GetType() confirms it and a cast gives me access to the sub class's properties.
 
BTW, I did search the new forum, and there wasn't any specific information.  I'll search the old forums as well, but so far my search on "polymorphism" is mostly turning up information about the older non-generic versions.

ajj3085 replied on Thursday, July 06, 2006

Here's some theads on this forum:

http://forums.lhotka.net/forums/thread/1181.aspx
http://forums.lhotka.net/forums/thread/250.aspx
http://forums.lhotka.net/forums/thread/2641.aspx

I searched for 'generics inheritance.'  Rocky has some comments in two of those threads I believe.

HTH
Andy

Copyright (c) Marimer LLC