views:

53

answers:

2

Hi folks,

I have an object (form) which contains a collection (.Fields) which I want to contain instances of a generic class (FormField).

The FormField, simply, is defined as such:

public class FormField<T>
{
    private Form Form;
    public T Value { get; set; }
    public string Name { get; set; }

    public void Process()
    {
        // do something
    }

    public FormField(Form form, string name, T value)
    {
        this.Name = name;
        this.Value = value;
        this.Form = form;
    }
}

This allows me to have FormField, FormField etc. and that part works great. What I want is a collection of "Formfields" regardless of the type, but I am forced into defining a type (it seems) such as:

public class Form
{

    string Code { get; set; }
    string Title { get; set; }
    int Year { get; set; }
    Guid ClientID { get; set; }

    ICollection<FormField<int>> Fields { get; set; }
}

What, I think, I want is an interface that allows me to abstract the type information and thus type the collection as instances of (for exxample) IFormField not FormField<>

But I can't see how to define this without strongly typing the collection in the interface...

Any help (including any alternative solutions!) would be greatly appreciated!

Thanks, Ben

+1  A: 

Create a non-generic interface or base class, which probably includes everything FormField does except the type-specific bits. Then you can have an ICollection<IFormField>. Obviously you won't be able to use this in a strongly-typed way, in terms of the type of field being used - but you can use all the non-type-specific bits of it (e.g. the name and the form).

Jon Skeet
thanks Jon, but if I understand you correctly then the interface would effectively have everything but the value property, which is a key element of the FormField..? Am I trying to use generics in the wrong way perhaps?
Ben
@Ben: Consider how you would try to *use* this collection. It could have a mixture of different form field types (int, string etc). How would you try to use the values from those form fields within `Form`? You won't know them at compile-time, or you'll be explicitly casting to the right type.
Jon Skeet
@Ben, you can declare a Value property in the IFormField interface, but you will have to declare it as Object. In the FormField<T> class, declare Value as T, and implement IFormField.Value explicitly.
Thomas Levesque
@Jon Skeet ahh, of course. I'm looking at this from the wrong angle. Cheers Jon, much appreciated
Ben
@Thomas Levesque - Cheers Thomas, I did try with the collection defined as type Object and it was causing me some problems, but I think Jon has prompted me to re-evaluate what I'm trying to do, and how! Thanks for your help
Ben
A: 

Here's some code to complete Jon's answer:

public interface IFormField
{
    string Name { get; set; }
    object Value { get; set; }
}

public class FormField<T> : IFormField
{
    private Form Form;
    public T Value { get; set; }
    public string Name { get; set; }

    public void Process()
    {
        // do something
    }

    public FormField(Form form, string name, T value)
    {
        this.Name = name;
        this.Value = value;
        this.Form = form;
    }

    // Explicit implementation of IFormField.Value
    object IFormField.Value
    {
        get { return this.Value; }
        set { this.Value = (T)value; }
    }
}

And in your form:

ICollection<IFormField> Fields { get; set; }
Thomas Levesque