views:

104

answers:

3

I'm trying to store a list of generic objects in a generic list, but I'm having difficulty declaring it. My object looks like:

public class Field<T>
{
    public string Name { get; set; }
    public string Description { get; set; }
    public T Value { get; set; }

    /*
    ...
    */
}

I'd like to create a list of these. My problem is that each object in the list can have a separate type, so that the populated list could contain something like this:

{ Field<DateTime>, Field<int>, Field<double>, Field<DateTime> }

So how do I declare that?

List<Field<?>>

(I'd like to stay as typesafe as possible, so I don't want to use an ArrayList).

+10  A: 

This is situation where it may benefit you to have an abstract base class (or interface) containing the non-generic bits:

public abstract class Field
{
    public string Name { get; set; }
    public string Description { get; set; }
}

public class Field<T> : Field
{    
    public T Value { get; set; }

    /*
    ...
    */
}

Then you can have a List<Field>. That expresses all the information you actually know about the list. You don't know the types of the fields' values, as they can vary from one field to another.

Jon Skeet
@Jon - Should the first class be a generic or just a simple class?
Giorgi
@Giorgi, `abstract class Field<T>` looks like a typo. I've taken the liberty of correcting it.
Anthony Pegram
He still has to cast to get the actual value type... but this is about the only solution that I can think of too, without an actual "tuple" type.
tames
@tames, he's in a better position because the elements of his list must inherit from Field (or implement IField, in my example). The list is still more strongly typed than a list of objects
Anthony Pegram
Doh, thanks for the fix folks. Still not feeling well :(
Jon Skeet
@anthony... I agree, and I have used both interface and base class solutions.
tames
+4  A: 

Perhaps implement an interface.

interface IField
{
}

class Field<T> : IField
{
}

...

List<IField> fields = new List<IField>() { new Field<int>(), new Field<double>() };
Anthony Pegram
This leaves him in the same position because IField won't contain the type (T). Not a whole lot different from just using `object` because he'll still have to cast to get the value.
tames
@tames, he's in a better position because the elements of his list must implement IField (or inherit from Field, in Jon's example). The list is still more strongly typed than a list of objects.
Anthony Pegram
@anthony... I agree, and I have used both interface and base class solutions.
tames
+2  A: 

You can't declare a list of generic types without knowing the generic type at compile time.

You can declare a List<Field<int>> or a List<Field<double>>, but there is no other common base type for Field<int> and Field<double> than object. So the only List<T> that could hold different kinds of fields would be List<object>.

If you want a more specific type for the list, you would have to make the Field<T> class inherit a class or implement an interface. Then you can use that for the generic type in the list.

Guffa