generics collection question

C

cwineman

Hello,

I'm hoping to do something using Generics, but I'm not sure it's possible.
Let's say I want to have a bunch of business objects and a data access class
cooresponding to each business object. For each business object, I would
have something like below:

public class Apple
{
//apple stuff
}

public class AppleDAL
{
public void UpdateApple( int appleID, Apple apple );
public Apple GetApple( int appleID );
public AppleList ListAllApples();
}

Currently, the AppleList collection class is a subclass of CollectionBase.
Everytime I add a new business object, I need to write a new DAL class and a
new CollectionBase subclass to act as the collection for that business
object:

/// <summary>
/// Type-safe collection for Apple objects
/// </summary>
[Serializable]
public class AppleList : System.Collections.CollectionBase
{
public AppleList {}

public Apple this[ int index ]
{
get{ return( Apple List[index] ); }
set{ List[index] = value; }
}

public int Add( Apple item ) { return( List.Add( item ) ); }

public int IndexOf( Apple item ) { return( List.IndexOf( item ) ); }

public void Insert( int index, Apple item ) { List.Insert( index,
item ); }

public void Remove( Apple item ) { List.Remove( item ); }
}


I am wondering if there is a way to use Generics to avoid writing the
CollectionBase subclass for every new business object. I'm not sure how I
would create a concrete type-safe collection for something new. So for an
new business object, orange:

public class Orange
{
//orange stuff
}

public class OrangeDAL
{
public void UpdateOrange( int orangeID, Orange orange );
public Orange GetOrange( int orangeID );
public OrangeList ListAllOranges();
}

Can I create an OrangeList class using Generics? Something like?

//this doesn't work
public class OrangeList <Orange>{}

-Corey
 
K

Kevin Spencer

Heck yes, Corey! It's quite simple:

using System.Collections.ObjectModel;

public class AppleList : Collection<Apple> {}

That's all you need. It already has the methods that you had to wire up
before, like Add, Remove, IndexOf, etc.

--
HTH,

Kevin Spencer
Microsoft MVP
Chicken Salad Surgery

Who is Mighty Abbott? A twin-turret scalawag.
 
W

wfairl

Sure, define a base DataCollection and DataRecord object. Then create
your base DAL entity class and collection and then you can create
custom classes on top of those (I say this because I'm guessing your
DAL is probably auto-generated).

Something like this for the DAL:

public abstract class OrangeCollectionBase<T> : DataCollection<T> where
T : OrangeBase, new()
{
}

Then your derived collection class would look like this:

public class Oranges : OrangeCollectionBase<Orange>
{
}
 
C

cwineman

Excellent.

I was fairly certain that it could be easily done, but I couldn't figure out
the syntax and I wasn't able to find an example showing what I wanted.

Thanks, guys.
 
C

Chris Dunaway

cwineman said:
I was fairly certain that it could be easily done, but I couldn't figure out
the syntax and I wasn't able to find an example showing what I wanted.

If you don't want to write your own class, you can just use the built
in List<> class:

public List<Orange> ListAllOranges();
 
J

Joanna Carter [TeamB]

<[email protected]> a écrit dans le message de (e-mail address removed)...

| Sure, define a base DataCollection and DataRecord object. Then create
| your base DAL entity class and collection and then you can create
| custom classes on top of those (I say this because I'm guessing your
| DAL is probably auto-generated).

This really isn't necessary, you can use List<T> or Collection<T> or any
other generic class without any further derivation. A DAL should be quite
capable of producing or iterating through such lists using reflection.

public static class DAL
{
public static List<T> RetrieveList<T>()
{
...
}

...
}

void test()
{
List<Customer> custList = DAL.RetrieveList<Customer>();

...
}

Joanna
 
C

Chris Mullins

Joanna Carter said:
This really isn't necessary, you can use List<T> or Collection<T> or any
other generic class without any further derivation. A DAL should be quite
capable of producing or iterating through such lists using reflection.
public static class DAL
{
public static List<T> RetrieveList<T>()
{
...
}

Just to be nitpicky, that code wouldn't pass FxCop validation (or Team
System Code Analysis).

For reason's I'm not quite clear on, you're not supposed to return a
List<T>. They recommend using the Generic classes found in the
System.Collections.ObjectModel namespace instead.

You can find more on this here:
http://msdn2.microsoft.com/en-us/library/ms182142.aspx
 
J

Joanna Carter [TeamB]

"Chris Mullins" <[email protected]> a écrit dans le message de (e-mail address removed)...

| Just to be nitpicky, that code wouldn't pass FxCop validation (or Team
| System Code Analysis).
|
| For reason's I'm not quite clear on, you're not supposed to return a
| List<T>. They recommend using the Generic classes found in the
| System.Collections.ObjectModel namespace instead.

Hmm, Do you know if IList<T> is equally frowned upon ?

| You can find more on this here:
| http://msdn2.microsoft.com/en-us/library/ms182142.aspx

Interesting but, as you say, the reasons really aren't all that clear. What
If I want to return a type that cannot be inherited, is that really so wrong
?

I personally use my own ReadOnlyList<T> class because ReadOnlyCollection<T>
raises exceptions on all the IList<T> implementing methods. To my mind, that
is a poor design choice; what is the point of supplying an interface that
provides most of its functionality by raising exceptions ? You could hardly
call that "implementation" :)

Joanna
 
C

Chris Mullins

"Chris Mullins" <[email protected]> a écrit dans le message de (e-mail address removed)...

| Just to be nitpicky, that code wouldn't pass FxCop validation (or Team
| System Code Analysis).
|
| For reason's I'm not quite clear on, you're not supposed to return a
| List<T>. They recommend using the Generic classes found in the
| System.Collections.ObjectModel namespace instead.

Hmm, Do you know if IList<T> is equally frowned upon ?

Code Analysis (via Team System) is perfectly happy with IList said:
| You can find more on this here:
| http://msdn2.microsoft.com/en-us/library/ms182142.aspx

Interesting but, as you say, the reasons really aren't all that clear.
What
If I want to return a type that cannot be inherited, is that really so
wrong
?

I agree. I recognized the issue in your code because I do it so often
myself. We've been trying to be diligant about using FxCop more, and this is
one of the things that keeps biting me.
I personally use my own ReadOnlyList<T> class because
ReadOnlyCollection<T>
raises exceptions on all the IList<T> implementing methods. To my mind,
that
is a poor design choice; what is the point of supplying an interface that
provides most of its functionality by raising exceptions ? You could
hardly
call that "implementation" :)

I agree here as well.

I would much rather have a true RealyOnly Interface. I want compile-time
errors, not run-time errors.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Chris said:
Code Analysis (via Team System) is perfectly happy with IList<T>. Seems to
be if one fails, they both should fail.

Maybe it has nothing to do with generics and it just wants
to enforce the good habit of returning interfaces instead
of concrete classes.

Arne
 
C

Chris Mullins

Arne Vajhøj said:
Maybe it has nothing to do with generics and it just wants
to enforce the good habit of returning interfaces instead
of concrete classes.

If only it were that simple.

The classes they recommend be returned, in the
System.Collections.ObjectModel namespace, are not interfaces. They're
standard classes.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Chris said:
If only it were that simple.

The classes they recommend be returned, in the
System.Collections.ObjectModel namespace, are not interfaces. They're
standard classes.

http://pluralsight.com/blogs/craig/archive/2005/10/21/15770.aspx
http://www.gotdotnet.com/team/fxcop/Docs/Rules/Design/DoNotExposeGenericLists.html

indicates that it is because System.Collections.ObjectModel.Collection
is intended to be extended while List is not.

No - it is not that obvious to me.

Arne
 
C

Chris Mullins

Arne Vajhøj said:
http://pluralsight.com/blogs/craig/archive/2005/10/21/15770.aspx
http://www.gotdotnet.com/team/fxcop/Docs/Rules/Design/DoNotExposeGenericLists.html

indicates that it is because System.Collections.ObjectModel.Collection
is intended to be extended while List is not.

That's the answer I saw as well - but it sure seems like a pretty weak
answer to me. I still don't understand their motivation, as there are a
number of cases where an List<T> is EXACTLY what I would want to return.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Chris said:
That's the answer I saw as well - but it sure seems like a pretty weak
answer to me. I still don't understand their motivation, as there are a
number of cases where an List<T> is EXACTLY what I would want to return.

Me too.

But ...

Arne
 
J

Joanna Carter [TeamB]

"Arne Vajhøj" <[email protected]> a écrit dans le message de XsXWg.20907$2g4.9052@dukeread09...

| http://pluralsight.com/blogs/craig/archive/2005/10/21/15770.aspx
|
http://www.gotdotnet.com/team/fxcop/Docs/Rules/Design/DoNotExposeGenericLists.html
|
| indicates that it is because System.Collections.ObjectModel.Collection
| is intended to be extended while List is not.

To quote a comment on the first blog :
Tomas, probably because they want you to derive from Collection<T>
to expose your strongly-typed collection classes in public APIs rather
than using List<T>. A

I thought the purpose of generic types was that you didn't have to derive
from them to provide strongly typed collections ! ? Huh ?


To quote the example in the first blog :

// This class satisfies the rule.
public class GenericIntegerCollection:
CollectionBase, IEnumerable<int>
{
public int Add(int value)
{
return InnerList.Add(value);
}

// Other method overrides using Int32.

public new IEnumerator<int> GetEnumerator()
{
foreach (int data in InnerList)
{
yield return data;
}
}
}

If I were designing a generic collection class, why would I use
CollectionBase to derive from ? This forces me to hold all my items in the
InnerList, which is an ArrayList !!! Surely the point of a generic
collection is that the items are stored as their native type, not
cast/boxed/unboxed on the way into/out of the storage ?

Methinks this train of thought has the smell of a .NET 1.1 programmer who
doesn't understand generics, enforcing their ideas on fxCop.

Joanna
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top