我的一个应用程序中有几个控件,它们都显然扩展了Control类。
我需要其中的几个来拥有一些共享接口,所以我创建了一个涵盖共享功能的接口。
有什么方法可以强制我的界面只能被赋予Control的子类?
即。 (伪)
interface IEmbed
class MyControl1 : Control, IEmbed
class MyControl2 : Control, IEmbed
class MyClass : IEmbed
理想情况下,我希望编译器在这里失败,因为MyClass尝试实现IEmbed,即使它不是控件。
我是以错误的方式解决这个问题还是有办法强制执行此行为?
修改
我被问到为什么要强制执行此行为。
我有一个方法,我想采取任何IEmbed实现,并将其作为子控件添加到另一个元素。
这一切都很好,但是Controls.Add()拒绝接受一个IEmbed对象,这不会编译。
我想如果我告诉编译器实现IEmbed的任何东西都必须是一个控件,它可能有用吗?
答案 0 :(得分:6)
不,在编译时无法强制执行此操作。
可以在运行时通过在使用obj is Control
作为obj
实例之前对IEmbed
进行框架代码测试来强制执行它。
更新:根据评论的反馈,看起来一个好的解决方案是继承中级abstract class EmbedControl : Control
并让您的方法接受EmbedControl
而不是IEmbed
(在这种情况下,实际上不需要保留接口,因为您只需在基类中使用abstract
方法。)
虽然上述方法可以很好地工作,但在某些情况下,强制“客户”类的实现者从您自己的中间类派生,即使您需要它们从“基类”派生{{1} } 同时。在这种情况下,另一种好的方法是使用泛型:
Control
答案 1 :(得分:5)
如果您需要执行此类检查,我建议您检查一下您的设计。界面只是一个契约,并没有对可以遵守它的内容施加限制。如果类型很重要,那么您应该尝试不同的方法,例如基类。 如何使用需要继承者来实现接口方法的抽象类(您可以在其中指定类型约束)?
interface IInterface
{
void Method1();
int Property1 { get; }
}
abstract class BaseClass: Control, IInterface
{
public abstract void Method1();
public abstract int Property1 { get; }
}
这只能确保从BaseClass派生的任何类都是Control和implements IInterface。
答案 2 :(得分:2)
我认为没有办法强制执行这样的操作 - 但我认为你真的不需要,因为你可以在运行时检查你的接口实例是否为Control。
但是:alternativley只使用抽象类(派生自Control)而不是接口:
abstract class EmbedControl
: Control
{
// your abstract members
}
class MyControl1 : EmbedControl
答案 3 :(得分:0)
什么不使用声明而检查T是控制?
另外,我同意上面写的内容,为什么界面应该是一种类型?这似乎是一个糟糕的设计,你知道你以后会将你的界面重新投入控件......
答案 4 :(得分:0)
实际上我无法想象为什么你需要它,但是Control是IComponent的后代。 也许你应该继承那个?
答案 5 :(得分:0)
嗯,我提供的解决方案非常难看,但在编译时失败了。
public interface IEmbed<T> where T: Control
{
}
public class A :Control, IEmbed<A>
{
}
//this fails at compile time as B does not inherit from Control class.
public class B : IEmbed<B>
{
}