编辑:--这是一个很好的设计问题,它是在重构可重用代码并将其组合到库中时提出的。
我正在将多年来经常使用的代码合并到一个库中,接口在这里发挥了很大的作用。在重构时,接口被分割的主要类别之一包括它们是为可变的还是不可变的场景而设计的。请考虑以下几点:
可变和不可变:
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的情况很奇怪,因为它没有理由接受泛型参数。但是,如果没有类,则不能仅对类强制使用。
我假设对于非泛型类型不存在约束,所以问题是是否有一种在运行时(或者在编译时更好)强制执行该约束的方法?除了泛型之外,属性也可以被限制(这里并不重要)。
当然,我可以使界面通用,但这不是一个好的理由,对吗?有什么优雅的方法来实现这一点吗?
发布于 2014-02-01 16:58:17
在C#语言中,无法阻止struct实现您的接口。任何类型都可以自由地实现任何接口,只要它能够满足这里描述的方法。
但是,您可以限制IInitializable的用法,使其只使用属于class类型的实现。例如
void M<T>(T value) where T : IInitializable, class 这可以仅用于将您的使用场景限制为class,从而获得您正在寻找的保证。
发布于 2014-02-01 17:07:29
您的代码看起来像Java。
C#支持操作符重载和用户定义的转换,因此您的ICopyable<T>看起来是多余的。
另外,除非您真的需要一个泛型的Clone()方法,否则您可能也可以很好地定义副本构造函数;您总是可以在内部使用双分派。所谓“真正需要”,我的意思是,算法真的是通用的吗?
编辑: Java中的 Clonable只是为了绕过它不支持模板/泛型这一事实。C#是这样做的,所以您的算法可以在类型上匹配,并且可以使用简单的复制构造器。
最后,WRT到Initialize(),如果它是一个通用的无参数方法,为什么不直接将代码放在构造函数中呢?对人们来说使用和理解它要容易得多。如果您的对象在构造时只被部分错误化,那么无论如何您需要检查并抛出InvalidOperationException,那么为什么要使您的界面复杂化呢?
如果Initialise()方法是为了支持多态性,那么它不应该在接口中,因为它是一个实现细节-接口是关于人们如何使用您的对象,而不是您如何构建它们;编译器对它们进行一些检查这一事实是次要的。
https://stackoverflow.com/questions/21500087
复制相似问题