我正在编写一个TemplateEngine,它允许我在基于文本的文件中使用自己的标记。我想在应用程序成熟时添加控件作为插件。目前我的结构如下:
interface IControl
string Id
object Value
class Label : IControl
string Id
string Value
class Repeater : IControl
string Id
List<IControl> Value
现在,您将使用Value属性立即在Repeater类中看到奇怪的部分。我希望在界面中将Value类型作为对象可以让我灵活地扩展控件。编译器不喜欢这个,我猜这是有充分理由的。
结论:我正在尝试让所有控件类实现相同的接口,但Value属性的类型不同。
有人有任何建议如何实现这个目标吗?
注意:请不要建议使用Spark View Engine进行模板化。我有理由为自己创造额外的工作。
答案 0 :(得分:9)
通常Repeater
会实现不同的内容,例如IItemsControl
。
编辑1
(为简洁而删除)
编辑2
好的,你当然可以使用显式接口实现:
interface IControl
{
string Id { get; set; }
object Value { get; set; }
}
class Label : IControl
{
public string Id { get; set; }
public string Value { get; set; }
object IControl.Value
{
get { return this.Value; }
set { this.Value = (string)value; }
}
}
class Repeater : IControl
{
public string Id { get; set; }
public IList<IControl> Value { get; set; }
object IControl.Value
{
get { return this.Value; }
set { this.Value = (IList<IControl>)value; }
}
}
答案 1 :(得分:3)
你也可以使用泛型:
interface IControl<T>
{
string ID{get;set;}
T Value{get;set;}
}
class SomeControl : IControl<string>
{
public string ID{get;set}
public string Value{get;set;}
}
class SomeOtherControl : IControl<int>
{
public string ID{get;set}
public int Value{get;set;}
}
如果只是一个需要更改的返回值,我比显式接口更好。但是,我认为如果你有几个属性,每个属性将返回一个不同的类型,你不希望有IControl。至少,我不会。在这种情况下,我会推荐显式接口。
当然,如果您无法访问IControl的来源,这将无效。
编辑:有一个错字。固定
答案 2 :(得分:1)
不,编译器不允许相同名称字段具有不同于派生类中接口中定义的数据类型。
属性(因为接口中不允许任何字段)应该在派生类中实现,并且它们需要具有相同的数据类型。所以,如果没有明确的声明,你不可能使用属性。
但是,如果你让一个函数返回Value,那么它可以工作,但是你需要检查返回类型,因为返回类型应该与函数匹配,否则你将得到错误,即接口的函数没有实现。
interface IControl
{
object Value();
}
class A : IControl
{
string m_value = string.Empty;
public object Value() { return m_value; }
};
class B : IControl
{
List<IControl> m_value = new List<IControl>();
public object Value() { return m_value; }
};
....
object o = new B().Value();
if (o is List<IControl>)
MessageBox.Show("List");
<强> [更新] 强>
如果明确定义属性的主体,则必须小心。如果没有仔细执行,那么为两个属性设置一个名称将是危险的。
如果这两个属性包含不同的定义,那么对于接口和类的最终使用来说,它是无法解释的。
public IList<IControl> Value
object IControl.Value
见这个例子:
...
class Repeater : IControl
{
List<IControl> m_Value = new List<IControl>();
public IList<IControl> Value
{
get { return this.m_Value; }
set { this.m_Value = (IList<IControl>)value; }
}
object IControl.Value
{
get
{
return this.m_Value;
}
set
{
this.m_Value = new List<IControl>();
this.m_Value.Add(new Label());
this.m_Value.AddRange((List<IControl>)value);
}
}
}
...
Repeater b = new Repeater();
IControl i = b;
List<IControl> list = new List<IControl>();
list.Add(new Repeater());
i.Value = list;
您可以观察到,当通过IControl添加数据时,Repeater中的列表容器将具有不同的值(因为IContainer.Value的显式定义)。