我有一个对象(表单),其中包含一个集合(.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
答案 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 ,这在以下情况下非常有用:
当您想要公开特定于类型的位时,您实际上是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。