views:

332

answers:

3

Chosen Solution

Thanks for the help everyone. I've decided to do the following.

public static class PersonCollection
{
    public static List<string> GetNames(RecordCollection<Person> list)
    {
        List<string> nameList = new List<string>(list.Count);

        foreach (Person p in list)
        {
            nameList.Add(p.Name);
        }

        return nameList;
    }
}



I'm trying to cast a generic collection RecordCollection to a derived collection PersonCollection, but I get a cast exception:

RecordCollection<Person> col = this.GetRecords<Person>(this.cbPeople);
PersonCollection people = (PersonCollection)col;

The reason I'm trying to do this is two-fold:

  1. The derived classes (eg, PersonCollection) can have instance methods (eg, GetLastNames) which shouldn't be in the base class.
  2. The method GetRecords is generic so I can get a collection of any Record objects.

What is the best approach to solve this in C# 2.0? What is the most elegant approach to solving this?

This is signature of GetRecords:

public RecordCollection<T> GetRecords<T>(ComboBox cb) where T : Record, new()

This is my base implementation:

public abstract class Record : IComparable
{
    public abstract int CompareTo(object other);
}

public class RecordCollection<T> : ICollection<T> where T : Record, new()
{
    private readonly List<T> list;

    public RecordCollection()
    {
        this.list = new List<T>();
    }

    // Remaining ICollection interface here
}

I have derived objects based on that base implementation as follows:

public class Person : Record
{
    public Person()
    {
        // This is intentionally empty
    }

    public string Name
    {
        get;
        set;
    }

    public override int CompareTo(object other)
    {
        Person real = other as Person;
        return this.Name.CompareTo(real.Name);
    }
}

public class PersonCollection : RecordCollection<Person>
{

}
+1  A: 

One option:

Make the methods on the derived types non-extension static methods that take in a specialized RecordsCollection ie

public static List<string>GetLastNames( RecordsCollection<Person> people )

so you can have usage along the lines of

RecordCollection<Person> somePeople = GetRecords<Person>(cbPeople);
List<string> lastNames = PersonCollecion.GetLastNames( somePeople );

It's not as pretty as the extension methods, but not too bad either.
edit: Removed erroneous info previously posted and replaced with potential solution

BioBuckyBall
-1: This issue is nothing to do with generic variance, and it still won't work in C# 4.0. This is because you cannot cast an object to a more derived type because it is not one, and this will never change.
Greg Beech
Oops, I read too quickly and misunderstood his problem. Thanks for the correction.
BioBuckyBall
+5  A: 

Your approach does not work because cast does not convert instances of one class to instances of another class.

You did not give the code of GetRecords<> method, but presumably GetRecords returns RecordCollection, and not PersonCollection (it has new RecordCollection somewhere in the code, doesn't it?).

You cannot cast RecordCollection to PersonCollection unless this particular instance actually is PersonCollection. Presicely because it does not have these additional methods.

This is like

SomeClass obj=new SomeClass();
DerivedClass o=(DerivedClass)obj; //throws exception
yu_sha
I added the signature for GetRecords
Joe
+2  A: 

Your best bet is to use some sort of factory call inside GetRecords, so that when you request a 'collection' of Person it will return PersonCollection as RecordCollection<Person>.

A naive implementation can use a few if's, else you can associate concrete collection type to record types via a Dictionary<Type,Type>.

leppie