对于非泛型接口,类似于Generics或AttributeUsage的约束

时间:2014-02-01 15:43:25

标签: c# .net generics interface constraints

编辑:在重构和将可重用代码组合到库中时,这是一个很好的设计问题。

我正在将经常使用的代码多年来整合到一个库中,接口在这里发挥了重要作用。在重构时,接口被拆分的主要类别之一包括它们是否是为可变或不可变场景而设计的。请考虑以下事项:

可变和不可变:

interface ICloneable<T> { T Clone (); }

不可变

interface ISomeInterface { T SomeFunc (); }

可变的

interface IInitializable { void Initialize (); }
interface ICopyable<T>: IInitializable { T CopyFrom (T source); T CopyTo (T destination); }

IInitializable的情况很奇怪,因为它没有理由接受通用参数。但是,没有一个,它不能仅强制使用类。

我假设非泛型类型不存在约束,所以问题是是否有办法在运行时强制执行此操作(或在编译时更好)?除了泛型之外,属性也可以被限制(这里不重要)。

当然我可以让界面通用,但这不是一个足够好的理由吗?有什么优雅的方法来实现这个目标吗?

2 个答案:

答案 0 :(得分:1)

C#语言无法阻止struct实现您的界面。任何类型都可以自由地实现任何接口,只要它能满足那里描述的方法即可。

但是,您可以将IInitializable的用法限制为仅适用于class类型的实现。例如

void M<T>(T value) where T : IInitializable, class 

这可用于将您的使用方案限制为class,从而获得您正在寻找的保证

答案 1 :(得分:0)

您的代码看起来像Java。

C#支持运营商重载和用户定义的转化,因此您的ICopyable<T>似乎是多余的。

另外,除非你真的需要一个通用的Clone()方法,否则你可能同样需要定义复制构造函数;你总是可以在内部使用双重调度。我的意思是,'真的需要'是算法真正的通用吗?

Java中的

编辑 Clonable是一个解决它不支持模板/泛型的事实。 C#可以,所以你的算法可以匹配类型,你可以使用简单易用的拷贝构造器。

最后,WRT到Initialize(),如果它是一个通用的无参数方法,为什么不把代码放在构造函数中呢?人们使用和理解它会容易得多。如果您的对象仅在构造中被部分地对象化,那么您无论如何都需要检查并抛出InvalidOperationException,那么为什么会使您的界面变得复杂?

如果Initialise()方法是支持多态,那么它不应该在接口中,因为它是一个实现细节 - 接口是关于人们如何使用你的对象,不是如何你建造它们;编译器对它们进行一些检查这一事实是次要的。