通用类型的集合

时间:2010-09-23 09:39:39

标签: c# generics collections interface

我有一个对象(表单),其中包含一个集合(.Fields),我想包含泛型类(FormField)的实例。

简单地说,FormField定义如下:

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

这允许我拥有FormField,FormField等,并且该部分非常有用。 我想要的是一个“Formfields”的集合,无论其类型如何,但我被迫定义一个类型(似乎),如:

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

我想,我想要的是一个接口,它允许我抽象类型信息,从而将集合键入为(例如)IFormField而不是FormField&lt;&gt;

的实例

但是如果没有在界面中强烈输入集合,我无法看到如何定义...

任何帮助(包括任何替代解决方案!)都将不胜感激!

谢谢,Ben

3 个答案:

答案 0 :(得分:11)

以下是完成Jon答案的一些代码:

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

以你的形式:

ICollection<IFormField> Fields { get; set; }

答案 1 :(得分:5)

创建一个非泛型接口或基类,其中可能包含除了类型特定位之外的所有内容FormField。然后你可以拥有ICollection<IFormField>。显然,就所使用的字段类型而言,您将无法以强类型方式使用它 - 但您可以使用它的所有非类型特定位(例如名称和形式)。

答案 2 :(得分:0)

另一个选项(替代Jon's answer)是应用 adapter pattern ,这在以下情况下非常有用:

  • 您无法修改类型,因此无法为其定义基本类型。
  • 或者,需要公开'类型特定位'(如Jon所说)。

当您想要公开特定于类型的位时,您实际上是have to create a non-generic wrapper。一个简短的例子:

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

在基类型中实现这种非泛型行为会有效地破坏Liskov substitution principle,这就是为什么我更喜欢将包装器方法作为I also argue in my blog post