与marker interfaces (没有任何成员的接口)相比,我们应该更喜欢属性( attributes ),这已经是discussed before on Stack Overflow了。Interface Design article on MSDN也断言了这个建议:
避免使用标记接口(没有成员的接口)。
自定义属性提供了标记类型的方法。有关自定义属性的更多信息,请参见编写自定义属性。如果可以将对属性的检查推迟到代码执行时,则首选自定义属性。如果您的场景需要编译时检查,则不能遵循此准则。
甚至有一个FxCop rule来执行这个建议:
避免空接口
接口定义提供行为或使用约定的成员。接口所描述的功能可由任何类型采用,而不管该类型出现在继承层次结构中的什么位置。类型通过提供接口成员的实现来实现接口。空接口不定义任何成员,因此也不定义可以实现的协定。
如果您的设计包含期望类型实现的空接口,则可能将接口用作标记或标识一组类型的一种方式。如果此标识将在运行时发生,则完成此操作的正确方法是使用自定义属性。使用属性的存在或不存在或属性的属性来标识目标类型。如果标识必须在编译时进行,则可以使用空接口。
本文只说明了您可能忽略该警告的一个原因:当您需要类型的编译时标识时。(这与界面设计文章是一致的)。
如果接口用于在编译时标识一组类型,则从该规则中排除警告是安全的。
这里有一个实际的问题:微软在框架类库的设计中没有遵守他们自己的建议(至少在一些情况下是这样):IRequiresSessionState interface和IReadOnlySessionState interface。ASP.NET框架使用这些接口来检查是否应该为特定的处理程序启用会话状态。显然,它不用于类型的编译时标识。他们为什么不这么做?我能想到两个潜在的原因:
obj is IReadOnlySessionState)比使用反射检查属性(type.IsDefined(typeof(SessionStateAttribute), true))更快。在大多数情况下,这种差异可以忽略不计,但对于ASP.NET运行时中的性能关键型代码路径,这种差异实际上可能很重要。但是,他们可以使用一些变通方法,比如缓存每个处理程序类型的结果。有趣的是,ASMX Web服务(具有类似的性能特征)实际上使用WebMethod attribute的EnableSession property来实现此目的。与第三方.NET语言使用属性修饰类型相比,更有可能支持
<%@ Page %> directive的EnableSessionState属性为实现上述接口的类型(可能在CodeDom的帮助下使用第三方语言)生成代码,因此使用接口而不是属性可能更有意义。使用标记接口而不是属性的有说服力的理由是什么?
这仅仅是一种(过早的)吗?是优化还是框架设计中的一个小错误?(他们认为是reflection is a "big monster with red eyes"吗?)有什么想法?
https://stackoverflow.com/questions/2086451
复制相似问题