I've read Rocky's post on using polymorphic children in collections, and started working with that idea, but I'm a bit confused about how to add items to the collection. Using Rocky's example....
Public Interface ILineItem
Inherits Csla.Core.IEditableBusinessObject
End Interface
<Serializable()> _
Public Class TaxableItem
Inherits Csla.BusinessBase(Of TaxableItem)
Implements ILineItem
' ...
End Class
<Serializable()> _
Public Class LineItems
Inherits Csla.BusinessListBase(Of LineItems, ILineItem)
' ...
End Class
What should the add method look like for the "LineItems" class. My first thought was to overload the AddNew method on the LineItems class to take in a variable with the taxableitemtype. Or is it better to make a public factory method for TaxableItem, so they can be created first then added to the collection?
Thoughts?
Jeff
Here is an example of what I'm using. It is a collection of questions, so for example....
IQuestion <- AbstractQuestion <- MultipleChoiceWithComment
Private
Sub Fetch(ByVal dr As SafeDataReader)RaiseListChangedEvents =
False Dim typeID As Integer While dr.Read()typeID = dr.GetInt32(
"QuestionTypeID") If typeID = QuestionTypeEnum.MultipleChoiceWithComments Then Me.Add(MultipleChoiceQuestionWithComment.GetMultipleChoiceQuestionWithComment(dr)) ElseIf typeID = QuestionTypeEnum.MultipleChoiceNoComments Then Me.Add(MultipleChoiceQuestion.GetMultipleChoiceQuestion(dr)) ElseIf typeID = QuestionTypeEnum.Comment Then Me.Add(CommentQuestion.GetCommentQuestion(dr)) End If End WhileRaiseListChangedEvents =
True End SubIt really helps. Thanks a lot.
CSLA doesn’t define how a root or parent object talks to
its children – that’s entirely up to you.
You have just a few options:
1.
Use a known base type that implements internal methods
2.
Use a known interface type that implements public methods
(public through the interface anyway)
3.
Use reflection (late binding) to invoke the methods by name
Which you choose is really up to you and your needs.
Number 1 is difficult due to the generic base class issue. There
are days I regret making the CSLA base classes generic… However, it would
be ideal, because it offers high performance and doesn’t add extra public
members to your interface.
Number 2 is unfortunate, because it opens the door for the UI
developer to “cheat” and use that interface. It muddies your object’s
API in a way that can only be solved by manual code review. But this is a high
performance option.
Number 3 has a negative performance impact and prevents the
compiler from finding simple typo errors in method names. However, this isn’t
a bad option in many cases, because it avoids both the generic base class issue
and eliminates the need to add public methods to your objects interface.
Rocky
From: Xabatcha
[mailto:cslanet@lhotka.net]
Sent: Friday, February 16, 2007 8:27 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Using Factory Methods with Polymorphic Children
In Collections
Thanx for an example....it helped.
But How did you solve the update method in Data Access region of child
list. As mentioned Rocky, my childs has implement IEditableBusinessObject,
which they do through my Interface IToken. Looks like this X509Token >
BusinessBase, IToken where IToken > IEditableBusinessObject.
Back to the child list...in Update method Update, Insert, DeleteSelft methods
of child are called. But my Childlist works only with interface IToken. There
are not those methods available.
So my Qs follows>
1. Do I need change type of item into specific type in every loop before
calling item methods( line 04,09,11)?
2. Am I missing some other Interface from csla?
3. Am I completly wrong?
Bye bye X.
Part of my Child list ......
01 internal void Update(IIdentity parent, DbTransaction transaction) {
02 RaiseListChangedEvents = false;
03 foreach (IToken item in D eletedList)
04 item.DeleteSelf(transaction);
05 DeletedList.Clear();
06
07 foreach (IToken item in this)
08 if (item.IsNew)
09 item.Insert(parent, transaction);
10 else
11 item.Update(transaction);
12 RaiseListChangedEvents = true;
13 }
RockfordLhotka:Number 2 is unfortunate, because it opens the door for the UI developer to “cheat” and use that interface. It muddies your object’s API in a way that can only be solved by manual code review. But this is a high performance option.
Good point Andy – that’ll teach me to answer questions before I’ve
had my morning coffee J
Rocky
From: ajj3085
[mailto:cslanet@lhotka.net]
Sent: Friday, February 16, 2007 10:39 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Using Factory Methods with Polymorphic
Children In Collections
RockfordLhotka:
Number 2 is unfortunate, because it opens the door for the UI developer to “cheat†and use that interface. It muddies your object’s API in a way that can only be solved by manual code review. But this is a high performance option.
Could the problem be solved by making the interface internal, and only
implementing the interface explicitly? I've done this where I needed an
interface for internal use but didn't want the UI to see it. I don't see
why that couldn't be done here.
Hi Rocky and Andy,
I am new to CSLA.NET and actually new to C# and OOP.
By the way Rocky, I just want to say that your books and framework are making my learning of
OOP and C# so much more enriching and enjoyable.
Having followed the advice in this thread carefully, I still do not see how you can make the interface
for a collection of polymorphic children internal.
It seems to me that in order to achieve a collection with polymorphic child objects as described in:
http://www.lhotka.net/Article.aspx?area=4&id=b8515cd9-7f8e-43df-9efd-cd958dfdc21a
we must define a public interface (e.g. public interface ILineItem) which inherits from
Csla.Core.IEditableBusinessObject.
This seems to force us to declare void Update, void Insert and void DeleteSelf in the said public interface so that each child must implement these methods as public (as opposed to internal).
Can one of you please explain explicitly how to avoid having Update, Insert, and DeleteSelf as public methods (thus manipulatable by the UI) coming from the public interface?
In other words, can you please explain to me explicitly by example why Andy really does have a point?
Thank you,
Emmanuel
Hi Andy,
Thank you very much for your quick reply.
I still can't seem to make the interface IMyInterface internal!
Did you leave out the fact that IMyInterface must inherit from Csla.Core.IEditableBusinessObject on purpose?
Here's what I have following the scheme in the first post of this thread:
namespace Test.Library
{
internal interface ILineItem : Csla.Core.IEditableBusinessObject {}
}
namespace Test.Library
{
[Serializable()]
public sealed class TaxableItem : BusinessBase<TaxableItem>,ILineItem
{ // ... }
}
namespace Test.Library
{
[Serializable()]
public sealed class DiscountableItem : BusinessBase<DiscountableItem>,ILineItem
{ // ... }
}
namespace Test.Library
{
[Serializable()]
public class LineItems : BusinessListBase<LineItems, ILineItem>
{ // ... }
}
When I try to compile this I get:
Error 1 Inconsistent accessibility: base class 'Csla.BusinessListBase<Test.Library.LineItems,Test.Library.ILineItem>' is less accessible than class 'Test.Library.LineItems'
This is before we even try to implement the interface explicitly.
I believe this is because the interface ILineItem must inherit from the interface
Csla.Core.IEditableBusinessObject (as explained by Rocky) which is **public**.
This, as I understand, implies that the interface ILineItem must be public in the first place
which is exactly what we are trying to avoid!
What am I not getting?
Thank you,
Emmanuel.
Copyright (c) Marimer LLC