views:

49

answers:

3

I'm a bit fuzzy on the best way to solve the problem of needing a list for each of my business objects that implements some overridden functions.

Here's the setup: I have a baseObject that sets up database, and has its proper Dispose() method All my other business objects inherit from it, and if necessary, override Dispose()

Some of these classes also contain arrays (lists) of other objects. So I create a class that holds a List of these. I'm aware I could just use the generic List, but that doesn't let me add extra features like Dispose() so it will loop through and clean up.

So if I had objects called User, Project and Schedule, I would create UserList, ProjectList, ScheduleList.

In the past, I have simply had these inherit from List<> with the appropriate class named and then written the pile of common functions I wanted it to have, like Dispose().

this meant I would verify by hand, that each of these List classes had the same set of methods. Some of these classes had pretty simple versions of these methods that could have been inherited from a base list class.

I could write an interface, to force me to ensure that each of my List classes has the same functions, but interfaces don't let me write common base functions that SOME of the lists might override.

I had tried to write a baseObjectList that inherited from List, and then make my other Lists inherit from that, but there are issues with that (which is really why I came here). One of which was trying to use the Find() method with a predicate.

I've simplified the problem down to just a discussion of Dispose() method on the list that loops through and disposes its contents, but in reality, I have several other common functions that I want all my lists to have.

What's the best practice to solve this organizational matter?

--------edit---added an example class that I'm trying to clean up with a better approach --This next code block is from my AppVarList class, which inherits straight from List. Right now I've got a mixture of styles on these lists, because I'm trying to find the best way to manage all these and consolidate the code:

[Serializable]
public class AppVarList : List<AppVar>
{
    private bool is_disposed = false;
    private bool _NeedsSaving = false;

    // Returns the AppVar, by name
    public AppVar this[string index]
    {
        get { return this.Find(f => f.Key == index); }
        set { this[this.FindIndex(f => f.Key == index)] = value; }
    }

    public AppVarList() { }

    // instantiates the object and connects it to the DB 
    // and populates it
    internal AppVarList(ref DBLib.DBAccess DA)
    {
        DataSet ds = 
            AppVar.SQLSelect(ref DA, 0, 0, false, "", "", "", "");

        foreach (DataRow dr in ds.Tables[0].Rows)
        {
            this.Add(new AppVar(ref DA, dr));
        }
        // Destroy the dataset object
        if (ds != null)-
A: 

You should make a common generic base class that inherits from System.Collections.ObjectModel.Collection<T>.

SLaks
And then.......what?
Robert Harvey
Then you add your methods to the base maybe as virtual so you can overide them and you can make your specific classes inherit from the base but for a specific type. e.g. ProjectList : BaseClass<Project>
Ben Robinson
so, make a baseList as class baseList<T> : System.Collections.ObjectModel.Collection<T> { //stuff here, maybe as virtual } then for my specific list classes class ProjectList : baseList<Project> { //override the stuff I want to override }
this doesn't appear to solve the problem of calling methods on the objects in the list, because without a type defined, it doesn't know if Dispose() for example exists(I'm trying this out right now and seeing the next hiccup)
`where T : IDisposable`. You can also make a generic `ForEach(Action<T>)` method. For more specific advice, please provide more detail.
SLaks
I've ammended the original question with a copy of a whole list class. Pretty much all my list classes have the same functionality, except for the iDictionary aspect (which I should have used instead of manually implementing iDictionary-like behavior)
Assuming the draft I gave for baseList<T> is correct, here's a function I need transformed to fit within it:public void ConnectDA(ref DBLib.DBAccess DA) { foreach (Project Item in this) if (!Item.IsDAReady()) Item.ConnectDA(ref DA); }Assume that Project is of baseObject, and everybody from baseObbject has those methods.In a way, I need T to be constrained to "anybody who IS baseObject"
A: 

Your best bet is to add extension methods to your IEnumerable collection i.e.

public static ScheduleListExtentions
{
    public static IEnumerable<ScheduleList> DoSomething(this IEnumerable<ScheduleList> mylist){
       //Act on your collection in some mannor here
       return mylist;
    } 
}
Owen
A: 

you could certainly pull up some of your functionality into a base class:

[Serializable]
public class BaseDataList<T> : List<T>
    where T : BaseObject // this is the key line, it ensure that
                         // T is a BaseObject so you can call 
                         //BaseObject methods on T, should allow for you
                         //to put more implementation in this class than
                         // you could otherwise
{
    private bool is_disposed = false;
    private bool _NeedsSaving = false;

    ///this assumes that key is a property on BaseObject that everything implements
    public T this[string index]
    {
        get { return this.Find(f => f.Key == index); }
        set { this[this.FindIndex(f => f.Key == index)] = value; }
    }

    public BaseDataList() { }

    // instantiates the object and connects it to the DB 
    // and populates it
    internal BaseDataList(ref DBLib.DBAccess DA)
    {
        DataSet ds = GetDataSet();

        foreach (DataRow dr in ds.Tables[0].Rows)
        {
            this.Add(new T(ref DA, dr));
        }
        // Destroy the dataset object
        if (ds != null)//...
    }
    //abstract methods for extensibility...
   protected abstract GetDataSet();
}

obviously this is just a rough sketch because i don't know all your requirements, but depending on how much implementation is shared in BaseObject you might be able to put a lot of functionality into BaseDataList (you should feel free to choose a better name). then all your other lists could just derive from BaseDataList.

For example if BaseObject implements IDisposable you could add this method to your class

protected void Dispose()
{
    is_disposing = true;
    foreach(T item in this)
    {
        item.Dispose();
    }
}

then you would only have to write it once

luke
this one nailed it. I'm cleaning out the trash right now.I didn't know I could put a WHERE T:baseObject as part of the inheritance from a generic. Seeing that syntax made it all obvious.Thanks
@ken-forslund Nothing says thanks like a check mark and an up vote :)
luke