开发者

Collection of generic types [duplicate]

开发者 https://www.devze.com 2023-01-17 19:15 出处:网络
This question already has answers here: Collection of generic types (10 answers) Closed 7 years ago. I have an object (form) which contains a collec开发者_如何学编程tion (.Fields) which I
This question already has answers here: Collection of generic types (10 answers) Closed 7 years ago.

I have an object (form) which contains a collec开发者_如何学编程tion (.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


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; }


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).


Another option (an alternative to Jon's answer) is to apply the adapter pattern, which can be useful when:

  • you are unable to modify the type, and can thus not define a base-type for it.
  • or, there is a need to expose 'type-specific bits' (as Jon put it).

When you want to expose type-specific bits, you effectively have to create a non-generic wrapper. A short example:

class NonGenericWrapper<T> : IAdaptor
{
    private readonly Adaptee<T> _adaptee;

    public NonGenericWrapper(Adaptee<T> adaptee)
    {
        _adaptee = adaptee;
    }

    public object Value
    {
        get { return _adaptee.Value; }
        set { _adaptee.Value = (T) value; }
    }
}

Implementing this non-generic behavior in a base-type would effectively break the Liskov substitution principle, which is why I prefer the wrapper approach as I also argue in my blog post.

0

精彩评论

暂无评论...
验证码 换一张
取 消