oo mess: how to make life complicated for yourself with inheritence and collections.please help

C

Charlie Bear

i've got myself into a bit of an oo mess. it's probably me
misunderstanding how oo works.

I've got a base class called "Feature" which some classes inherit. in
the database i've stored the data in a table along with a type id to
tell me what type of feature it is. ie a poll feature has an id of two
and has the properties of feature plus a poll id which links to a poll
table. the poll feature has seperate methods that the base feature
doesn't need. hence the need for inheritence.

what i want to do is get the list of features from the database cast
them in to their correct type (by doing a switch on the type id) and
add them to a collection. trouble is i don't want to have to add all
their common properties in the switch as i would be repeating myself
over and over. i can't add the values to the base feautre class then
cast it becuase it doens't work. is there any way i can using generics
or reflection to do what i need? here is an example of what i am doing
at the moment what can i do to make this easier to manage?

private void getFeaturesSql(System.Data.SqlClient.SqlDataReader dr)
{


if(dr.HasRows)
{
while(dr.Read())
{


switch (dr.GetInt32(4))
{
case 1://standard text feature
Cve.Core4.Business.TextFeature tf = new
TextFeature();
tf.FeatureId = dr.GetInt32(0);
tf.Title = dr.GetString(1);
tf.FeatureBody = dr.GetString(2);
tf.Type = 1;
tf.ArticleId = dr.GetInt32(5);
tf.Slot = dr.GetInt32(6);
tf.Filename = dr.GetString(7);
tf.Enabled = dr.GetBoolean(8);
tf.Order = dr.GetInt32(9);
tf.Date = dr.GetDateTime(10);

features.Add(tf);
break;

case 2://poll
Cve.Core4.Business.PollFeature pf = new
PollFeature();
pf.FeatureId = dr.GetInt32(0);
pf.Title = dr.GetString(1);
pf.FeatureBody = dr.GetString(2);
pf.Type = 2;
pf.PollId = dr.GetInt32(3);
pf.ArticleId = dr.GetInt32(5);
pf.Slot = dr.GetInt32(6);
pf.Filename = dr.GetString(7);
pf.Enabled = dr.GetBoolean(8);
pf.Order = dr.GetInt32(9);
pf.Date = dr.GetDateTime(10);

features.Add(pf);
break;
}

}
}
}
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Charlie said:
i've got myself into a bit of an oo mess. it's probably me
misunderstanding how oo works.

I've got a base class called "Feature" which some classes inherit. in
the database i've stored the data in a table along with a type id to
tell me what type of feature it is. ie a poll feature has an id of two
and has the properties of feature plus a poll id which links to a poll
table. the poll feature has seperate methods that the base feature
doesn't need. hence the need for inheritence.

what i want to do is get the list of features from the database cast
them in to their correct type (by doing a switch on the type id) and
add them to a collection. trouble is i don't want to have to add all
their common properties in the switch as i would be repeating myself
over and over. i can't add the values to the base feautre class then
cast it becuase it doens't work. is there any way i can using generics
or reflection to do what i need? here is an example of what i am doing
at the moment what can i do to make this easier to manage?

You can't create an object of the base class and cast it to a subclass,
but you can do it the other way around.

Create each object in the switch and assign it to a reference of the
base class. After the switch you can use the reference to set the
properties, regardless of the actual type of the object.

Example:

BaseClass feature;
switch (wantedClass) {
case Class1:
SomeObject.Member1 = new SubClass1();
feature = SomeObject.Member1;
break;
case Class2:
SomeObject.Member2 = new SubClass2();
feature = SomeObject.Member1;
break;
}
feature.Some = 1;
feature.Other = 2;
 
O

Otis Mukinfus

i've got myself into a bit of an oo mess. it's probably me
misunderstanding how oo works.

I've got a base class called "Feature" which some classes inherit. in
the database i've stored the data in a table along with a type id to
tell me what type of feature it is. ie a poll feature has an id of two
and has the properties of feature plus a poll id which links to a poll
table. the poll feature has seperate methods that the base feature
doesn't need. hence the need for inheritence.

what i want to do is get the list of features from the database cast
them in to their correct type (by doing a switch on the type id) and
add them to a collection. trouble is i don't want to have to add all
their common properties in the switch as i would be repeating myself
over and over. i can't add the values to the base feautre class then
cast it becuase it doens't work. is there any way i can using generics
or reflection to do what i need? here is an example of what i am doing
at the moment what can i do to make this easier to manage?

private void getFeaturesSql(System.Data.SqlClient.SqlDataReader dr)
{


if(dr.HasRows)
{
while(dr.Read())
{


switch (dr.GetInt32(4))
{
case 1://standard text feature
Cve.Core4.Business.TextFeature tf = new
TextFeature();
tf.FeatureId = dr.GetInt32(0);
tf.Title = dr.GetString(1);
tf.FeatureBody = dr.GetString(2);
tf.Type = 1;
tf.ArticleId = dr.GetInt32(5);
tf.Slot = dr.GetInt32(6);
tf.Filename = dr.GetString(7);
tf.Enabled = dr.GetBoolean(8);
tf.Order = dr.GetInt32(9);
tf.Date = dr.GetDateTime(10);

features.Add(tf);
break;

case 2://poll
Cve.Core4.Business.PollFeature pf = new
PollFeature();
pf.FeatureId = dr.GetInt32(0);
pf.Title = dr.GetString(1);
pf.FeatureBody = dr.GetString(2);
pf.Type = 2;
pf.PollId = dr.GetInt32(3);
pf.ArticleId = dr.GetInt32(5);
pf.Slot = dr.GetInt32(6);
pf.Filename = dr.GetString(7);
pf.Enabled = dr.GetBoolean(8);
pf.Order = dr.GetInt32(9);
pf.Date = dr.GetDateTime(10);

features.Add(pf);
break;
}

}
}
}

I may be missing something here, but it seems to me both of your objects share
the same properties except for PollID.

So inheriting two types from Feature you might look at making one inherited
class with all the properties (at this time that appears to be the PollFeature
object) and get rid of the other one. Your already storing the Feature's type
in the Type property, so you can identify a feature's type from that property
when you need to. The designer of the database probably intended this sort of
thing anyway because he/she included the TYPE column.

If you do this you would not need the switch. You would do it like this:

Cve.Core4.Business.TextFeature tf = new FeatureWithoutInheritence();
f.FeatureId = dr.GetInt32(0);
f.Title = dr.GetString(1);
f.FeatureBody = dr.GetString(2);
f.Type = GetInt32(4);
if(f.Type == 2)
{
f.PollID = dr.GetInt32(3);
}
f.ArticleId = dr.GetInt32(5);
f.Slot = dr.GetInt32(6);
f.Filename = dr.GetString(7);
f.Enabled = dr.GetBoolean(8);
f.Order = dr.GetInt32(9);
f.Date = dr.GetDateTime(10);

features.Add(f);

Naturally, since I don't know how you are using the object, what I suggested may
not be appropriate, but it's a way of avoiding the switch statement.

Good luck with your project,

Otis Mukinfus

http://www.otismukinfus.com
http://www.arltex.com
http://www.tomchilders.com
http://www.n5ge.com
 
C

Charlie Bear

Thanks guys. both solutions are viable and useful. My solution to the
problem was a little more complicated (think i might take a simpler
approach):

public static System.Collections.ArrayList
GetFeaturesSql(System.Data.SqlClient.SqlDataReader dr)
{
//create collection object - should use generics really.
System.Collections.ArrayList al = new ArrayList();
if (dr.HasRows)
{
while (dr.Read())
{

//work out the class name...
string className = "Business." +
FeatureController.GetClassNameFromType(Convert.ToInt32(dr["type"]));
Assembly assembly =
Assembly.GetExecutingAssembly();
AssemblyName assemblyName =
assembly.GetName();
Type t = assembly.GetType(assemblyName.Name + "."
+ className);
//Create the object
object newFeature = Activator.CreateInstance(t);
//get the properties for the type
PropertyInfo[] objPropertiesArray =
t.GetProperties();
//cycle through the data reader columns
for (int i = 0; i < dr.FieldCount - 1; i++)
{
//find the property on the new object
foreach (PropertyInfo p in objPropertiesArray)
{
//if the data reader name and dr name is
the same then get the type and add it (achieved by aliases in the
sproc).
string drName = dr.GetName(i);
if (p.Name == drName)
{
switch (p.PropertyType.ToString())
{

case "System.String":
p.SetValue(newFeature,
dr.GetString(i), null);
break;
case "System.DateTime":
p.SetValue(newFeature,
dr.GetDateTime(i), null);
break;
case "System.Int32":
p.SetValue(newFeature,
dr.GetInt32(i), null);
break;
case "System.Boolean":
p.SetValue(newFeature,
dr.GetBoolean(i), null);
break;
}
}

}
}
// add the new object to the collection.
al.Add(newFeature);
}
}
return al;

}
 
Top