473,406 Members | 2,312 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Polymorphism & Collections

I'm relatively new to C# and polymorphism, so what I'm trying to accomplish
may not be possible, or there may be a totally different approach that I
should be taking.

I have a base class (MyBase) and a collection of MyBase objects
(MyBaseCollection). Now, I also have an extension to MyBase (MyExtendedBase
: MyBase) that has additional properties. And lastly, I have a collection
of MyExtendedBase objects(MyExtendedBaseCollection : MyBaseCollection).

I have a data layer that has a method (GetMyBaseCollection) that retrieves
records from the database, and populates a MyBaseCollection with these
records. However, there are cases where I need to use this method to
populate a MyExtendedBaseCollection. But here's the catch -- I want my data
layer to be unaware (and independent) of MyExtendedBase and
MyExtendedBaseCollection.

I have tried several different ways to accomplish this, but no matter what I
do, I end up needing to up-cast MyBase to MyExtendedBase, which is illegal
in C#. I need my data layer to be able to accept and populate a
MyBaseCollection (with it possibly being a sub class of a
MyExtendedBaseCollection) with MyBase objects (with them possibly being sub
classes of MyExtendedBase), and then when the collection is returned, the
items in the collection are of the appropriate type (depending on the type
of collection passed in).

I have read about different design patterns (namely Decorator and
Composite), but am not sure if they apply to my situation, and if so, how to
implement them accordingly.

Again, I may be doing something totally illogical, so I'm open to any
suggestions you may have. Also, if I have not provided enough info, let me
know and I will follow up.

Thanks in advance.

Jerad
Mar 15 '06 #1
14 2556
I think your're pretty close. If you have a base class, then you should
have no problem passing MyExtendedBaseCollection as a MyBaseCollection
object. This is the power of polymorphism.

A couple of your statements:
need my data layer to be able to accept and populate a
MyBaseCollection (with it possibly being a sub class of a
MyExtendedBaseCollection) with MyBase objects (with them possibly being sub
classes of MyExtendedBase),


MyExtendedBase and MyExtendedBaseCollection are sub classes of MyBase
and MyBaseCollection.

When you say a "subclass" it means that it inherits from a base class
or abstract class. I think you have the terminology backwards.

If you are trying to cast MyBase to MyExtendedBase, this is not going
to work. When you need to pass around a specialized type of class, but
dont want to code additional methods (apart from special functionality)
then you cast your dervied or subclasses (MyExtendedBase) to type
MyBase, you can then pass it around as normal, any methods that are in
the base class that you override in the subclass, can be called as
normal because both the base class and sub class have definitions for
those methods.

Another way to accomplish this would be to use interfaces.

As far as the design patterns, this is something I am still learning as
well, I have found that if you dont understand the design pattern
completely, then dont use it at all. because chances are is that you
will miuse the pattern, and create more headaches then solutions.

hope my comments help!

Mar 15 '06 #2
Jerad Rose wrote:
do, I end up needing to up-cast MyBase to MyExtendedBase, which is illegal
That's a down-cast. It's "legal" (staticly valid), but if the actual
object instance casted is not an instance of MyExtendedBase the cast
will fail and throw an exception.
Again, I may be doing something totally illogical, so I'm open to any
suggestions you may have. Also, if I have not provided enough info, let me
know and I will follow up.


Let the data-layer, that should be generic in the types, accept the
data-structure to fill items into as an argument. If your data layer
needs to construct "unknown" type objects from data you can have a look
at the factory-pattern. The data-layer can accept, as a parameter, a
factory that is given the data to parse and create an object from that.

BTW: Are you in C#1 or 2?

Decorator and composite are completely unrelated to your problem.

--
Helge Jensen
mailto:he**********@slog.dk
sip:he**********@slog.dk
-=> Sebastian cover-music: http://ungdomshus.nu <=-
Mar 15 '06 #3
Bob
Hi Jerad,
You only need one collection. The one for the base class.
When you're pulling in data from the database test the attribute(s) that
mark the difference between Mybase and MyExtendedBase before instantiating
the object that you are going to add to the collection.
bool MyDatabaseGetRoutine(ref collection col)
{
SQlDataCommand etc setup.
MyBase b;
While MyDatareader.read
{
If(MyDataReader.GetString(say5) == dbNull) //Instantiate a MyBase
b=new MyBase();
else // Instantiate a MyBaseExtended
b= new MyBaseExtended();
// Now fill the common (MyBase) properties
b.Common1 = MyDataRead.GetString(0);
b.Common2 = MyDataRead.GetString(1);
Test again for type.
if (b.GetType().ToString()=="MyBaseExtended")

{

// Fill the extended properties

}

col.add(b); Adding to collection regardless of Instantiation.

When you come to use the collection iterate across it with a base type
variable

bool LetsUnpackIt(collection col)

foreach (mybase b in col)

{

if (b.gettype().ToString()=="MyBase")

//Do the mybase things

else

// Do the myBaseExtended things

HTH

Bob

"Jerad Rose" <no@spam.com> wrote in message
news:ea**************@TK2MSFTNGP09.phx.gbl...
I'm relatively new to C# and polymorphism, so what I'm trying to accomplish may not be possible, or there may be a totally different approach that I
should be taking.

I have a base class (MyBase) and a collection of MyBase objects
(MyBaseCollection). Now, I also have an extension to MyBase (MyExtendedBase : MyBase) that has additional properties. And lastly, I have a collection
of MyExtendedBase objects(MyExtendedBaseCollection : MyBaseCollection).

I have a data layer that has a method (GetMyBaseCollection) that retrieves
records from the database, and populates a MyBaseCollection with these
records. However, there are cases where I need to use this method to
populate a MyExtendedBaseCollection. But here's the catch -- I want my data layer to be unaware (and independent) of MyExtendedBase and
MyExtendedBaseCollection.

I have tried several different ways to accomplish this, but no matter what I do, I end up needing to up-cast MyBase to MyExtendedBase, which is illegal
in C#. I need my data layer to be able to accept and populate a
MyBaseCollection (with it possibly being a sub class of a
MyExtendedBaseCollection) with MyBase objects (with them possibly being sub classes of MyExtendedBase), and then when the collection is returned, the
items in the collection are of the appropriate type (depending on the type
of collection passed in).

I have read about different design patterns (namely Decorator and
Composite), but am not sure if they apply to my situation, and if so, how to implement them accordingly.

Again, I may be doing something totally illogical, so I'm open to any
suggestions you may have. Also, if I have not provided enough info, let me know and I will follow up.

Thanks in advance.

Jerad

Mar 15 '06 #4
Thanks for the responses, guys.

To clarify on a few comments:

dkode wrote:
When you say a "subclass" it means that it inherits from a base class or abstract class. I think you have the terminology backwards.
Yeah, I guess I was thinking the "subclass" would be the more generic one
and have fewer members, sort of like a subset. Thanks for the
clarification.

dkode wrote:
I have found that if you dont understand the design pattern completely, then dont use it at all.
I tend to agree with you there, which was why I wouldn't have used them
unless somebody could have helped me understand them.

Helge Jensen wrote:
That's a down-cast. It's "legal" (staticly valid), but if the actual object instance casted is not an instance of MyExtendedBase the cast will fail and throw an exception.
Yeah, that's what I meant (see example below). But I did get the
up-/down-cast confused. But I think I've seen other people posting this
backwards as well.

Helge Jensen wrote:
The data-layer can accept, as a parameter, a
factory that is given the data to parse and create an object from that.
It seems this is the recommended way to go. And I had thought about going
this route originally, but the thing I don't like about using a factory is
that my data layer is dependent on this factory, which it turn is dependent
on my extended class -- which I was trying to avoid. However, I understand
this may be my only option.

Helge Jensen wrote:
BTW: Are you in C#1 or 2?
1.1

Bob wrote:
You only need one collection. The one for the base class.
Theoretically true, but I want my collections to be type-safe, so that
casting isn't required to access the extended members. However, if doing
this would remove the dependence of my data layer on my extended class, I
would go this route.
When you're pulling in data from the database test the attribute(s) that mark the difference between Mybase and MyExtendedBase before instantiating the object that you are going to add to the collection.


This is similar to the factory concept, and requires the same dependency of
my data layer on my extended object/properties. The data layer will not
need access to any of the extended properties, so I would prefer to not
require this dependency. But again, I may not have that option.

Repeating what I said in my original post, here is my setup:

MyBase

MyBaseCollection

MyExtendedBase : MyBase

MyExtendedBaseCollection : MyBaseCollection

I can pass an instance of MyExtendedBaseCollection to the data layer, caste
as MyBaseCollection. But when my data layer creates new MyBase objects and
adds them to the collection, there's no way I can down-cast them to
MyExtendedBase when I return from the data layer. I would think there would
be a way to have a base collection get populated with base objects, without
introducing the dependency of the underlying method on the extended
class/collection. It seems this would be a common need, but it sounds like
my options aren't as elegant as "best practices" encourage.

Dkode, you mentioned interfaces. Would the use of interfaces help
accomplish my goals?

Thanks again.

Jerad


Mar 15 '06 #5
If you want "type safety" (more likely you want to avoid the upcast
here) then you should consider a move to 2.0 and generics. You can do
something similar to this, I've done it in my own data
objects/collections

Something like:
MyBaseObj{ }
MyBaseCollection<T> : ICollection<T> where T : MyBaseObj
{
public T this[int index]
{
get
{
...
}
}

...
}

Then MyDerivedObj :MyBaseObj for your derived record obj
and MyDerivedCollection : MyBaseCollection<MyDerivedObj> for your
derived collection of derived record objects

Mar 16 '06 #6
Thats interesting how you accomplish this with generics. I need to read
up more on generics. All I have used them for is for a List collection
within another class. What does using the <T> accomplish? You don't
have to specify the type?

Mar 16 '06 #7
dkode wrote:
Thats interesting how you accomplish this with generics. I need to read
up more on generics. All I have used them for is for a List collection
within another class. What does using the <T> accomplish? You don't
have to specify the type?


You don't specify the type when writing the generic type; you specify
it when you *use* the type.

It's well worth reading up on generics - it's a massive topic though!

Jon

Mar 16 '06 #8
For those interested, I am posting below what ended up being the ultimate
solution I came to. This accomplishes both of my goals:

1) Type safety
2) Independence of data layer on extended classes

Your feedback is welcomed and appreciated.

Thanks.
Jerad

//Polymorphic Collections Example

public class MyBaseClass
{
//base member implementation
}

public class MyBaseCollection : ICollection
{
protected ArrayList _innerList;

public MyBaseClass this[int index]
{
get { return (MyBaseClass)_innerList[index]; }
}

public virtual MyBaseClass AddNewItem()
{
MyBaseClass newBaseItem = new MyBaseClass();
_innerList.Add(newBaseItem);
return newBaseItem;
}

//standard collection member implementation
}

public class MyExtendedClass : MyBaseClass
{
public string MyExtendedProperty
{
//get/set implementation
}
}

public class MyExtendedCollection : MyBaseCollection
{
public new MyExtendedClass this[int index]
{
get { return (MyExtendedClass)base._innerList[index]; }
}

public override MyBaseClass AddNewItem()
{
MyExtendedClass newExtendedItem = new MyExtendedClass();
_innerList.Add(newExtendedItem);
return newExtendedItem;
}
}

public class MyDataLayer
{
public void GetRecords(MyBaseCollection myBaseCol)
{
//database implementation

while(dr.Read())
{
//This is critical -- using the collection's AddNewItem
//to instantiate the object will ensure the proper type
//is being instantiated. If the collection is an
//instance of MyExtendedCollection, it will create and
//add an instance of MyExtendedClass to the collection.
//Otherwise, it will add an instance of MyBaseClass.

MyBaseClass myBase = myBaseCol.AddNewItem();

//set myBase's base properties
}
}
}

public class TestClient
{
public void Main()
{
MyDateLayer myDL = new MyDataLayer();

//This will pass an instance of a base collection to the data layer
MyBaseCollection myBaseCol = new MyBaseCollection();
myDL.GetRecords(myBaseCol);
myBaseCol[0].MyExtededProperty = "Not legal";

//This will pass an instance of an extended collection to the data
layer
MyExtendedCollection myExtCol = new MyExtendedCollection();
myDL.GetRecords(myExtCol);
myExtCol[0].MyExtededProperty = "Legal";
}
}
Mar 16 '06 #9
I have a quick question about your implementation.

Doesn't this violate n-tier design because the datalayer has knowledge
of the business layer objects? I thought the data layer was only
supposed to return records (DataReader) in this instance, or is all of
this code in your data layer?
From other NG postings, I've had people tell me that the Data Layer has

NO knowledge of business layer objects, doing so violates proper N-Tier
design and tighly couples your business layer with your data layer.

Mar 16 '06 #10
We use following layers, from bottom to top:

Business Entities
Data Layer
Business Layer
Client

So, our data layer *is* aware of the business entities, but *not* the
business layer. The business entity layer is just the logical schema for
our data. So, instead of our data layer returning a generic set of records
(DataReader or DataSet), it returns typed objects representing our data.
Then the business layer applies any business logic/rules to the data before
returning it to the client.

"dkode" <dk****@gmail.com> wrote in message
news:11**********************@v46g2000cwv.googlegr oups.com...
I have a quick question about your implementation.

Doesn't this violate n-tier design because the datalayer has knowledge
of the business layer objects? I thought the data layer was only
supposed to return records (DataReader) in this instance, or is all of
this code in your data layer?
From other NG postings, I've had people tell me that the Data Layer has

NO knowledge of business layer objects, doing so violates proper N-Tier
design and tighly couples your business layer with your data layer.

Mar 17 '06 #11
I see. Is there any code duplication between the Business Entities
structure and the Business Layer?

Mar 17 '06 #12
No, these are completely independent of each other. The business entity
classes only consist of typed properties and collections, representing our
data schema. The business layer uses the data layer to populate the
business entities, and then carries out any business logic implementation
needed.

"dkode" <dk****@gmail.com> wrote in message
news:11**********************@j52g2000cwj.googlegr oups.com...
I see. Is there any code duplication between the Business Entities
structure and the Business Layer?

Mar 17 '06 #13
I see how you have it configured now.

I have never tried to setup my apps that way, I've always had the
business entities in the same layer as the business rules. I guess this
does allow for better seperation, and for getting typed data from your
data layer rather then generic datareader/dataset.

Have you had success with structuring your apps in this way? I might
opt to try this in my next project (planning stages now)

Mar 17 '06 #14
Yeah, this seems to work well. One of the better articles I've found to
help me understand designing the different layers/tiers is this one on MSDN:

http://msdn.microsoft.com/library/de...tml/BOAGag.asp

Check that out if you haven't already read it. There are some other good
articles on MSDN along these lines as well, but this deals specifically w/
data access layer component design.

HTH.

Jerad

"dkode" <dk****@gmail.com> wrote in message
news:11**********************@e56g2000cwe.googlegr oups.com...
I see how you have it configured now.

I have never tried to setup my apps that way, I've always had the
business entities in the same layer as the business rules. I guess this
does allow for better seperation, and for getting typed data from your
data layer rather then generic datareader/dataset.

Have you had success with structuring your apps in this way? I might
opt to try this in my next project (planning stages now)

Mar 18 '06 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: The Directive | last post by:
I can't understand why in this folling example the message "Base.Draw()" is printed. Shouldn't "Derive.Draw" be printed because of polymorphism? How can I rewrite this example using a vector to...
12
by: Steve Jorgensen | last post by:
The classing Visual Basic and VBA support for polymorphism, let's face it, is a bit on the weak side, and built-in support for inheritance is non-existent. This little essay is about some patterns...
2
by: Marc | last post by:
Given a class 'Invoice' with a property 'public IMyColl<IInvoiceLine> InvoiceLines' where 'IMyColl<T> : IList<T>' i would like to detect by reflection that 'InvoiceLines' is a...
15
by: rwf_20 | last post by:
I just wanted to throw this up here in case anyone smarter than me has a suggestion/workaround: Problem: I have a classic producer/consumer system which accepts 'commands' from a socket and...
4
by: nhmark64 | last post by:
Hi, Does System.Collections.Generic.Queue not have a Synchronized method because it is already in effect synchronized, or is the Synchronized functionality missing from...
13
by: Krivenok Dmitry | last post by:
Hello all! Perhaps the most important feature of dynamic polymorphism is ability to handle heterogeneous collections of objects. ("C++ Templates: The Complete Guide" by David Vandevoorde and...
9
by: James Crosswell | last post by:
I'm not sure if I'm going about this the right way - it may be that Generics might be able to help me out here... but here goes: I have three classes as follows class BaseEdit class WidgetEdit:...
3
by: dippykdog | last post by:
I have an IRange interface defined as... Public Interface IRange Property Min() As Object Property Max() As Object End Interface ....and I want to implement that in different kinds of range...
1
by: mattmao | last post by:
I am brand new to C#.NET so here is my trial on this lab exercise: using System; using System.Collections.Generic; using System.Text; using System.Collections; namespace lab02exec { ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.