首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用标记接口代替属性的令人信服的理由

使用标记接口代替属性的令人信服的理由
EN

Stack Overflow用户
提问于 2010-01-18 21:57:28
回答 6查看 7.1K关注 0票数 58

marker interfaces (没有任何成员的接口)相比,我们应该更喜欢属性( attributes ),这已经是discussed before on Stack Overflow了。Interface Design article on MSDN也断言了这个建议:

避免使用标记接口(没有成员的接口)。

自定义属性提供了标记类型的方法。有关自定义属性的更多信息,请参见编写自定义属性。如果可以将对属性的检查推迟到代码执行时,则首选自定义属性。如果您的场景需要编译时检查,则不能遵循此准则。

甚至有一个FxCop rule来执行这个建议:

避免空接口

接口定义提供行为或使用约定的成员。接口所描述的功能可由任何类型采用,而不管该类型出现在继承层次结构中的什么位置。类型通过提供接口成员的实现来实现接口。空接口不定义任何成员,因此也不定义可以实现的协定。

如果您的设计包含期望类型实现的空接口,则可能将接口用作标记或标识一组类型的一种方式。如果此标识将在运行时发生,则完成此操作的正确方法是使用自定义属性。使用属性的存在或不存在或属性的属性来标识目标类型。如果标识必须在编译时进行,则可以使用空接口。

本文只说明了您可能忽略该警告的一个原因:当您需要类型的编译时标识时。(这与界面设计文章是一致的)。

如果接口用于在编译时标识一组类型,则从该规则中排除警告是安全的。

这里有一个实际的问题:微软在框架类库的设计中没有遵守他们自己的建议(至少在一些情况下是这样):IRequiresSessionState interfaceIReadOnlySessionState interface。ASP.NET框架使用这些接口来检查是否应该为特定的处理程序启用会话状态。显然,它不用于类型的编译时标识。他们为什么不这么做?我能想到两个潜在的原因:

  1. Micro-optimization:检查对象是否实现了接口(obj is IReadOnlySessionState)比使用反射检查属性(type.IsDefined(typeof(SessionStateAttribute), true))更快。在大多数情况下,这种差异可以忽略不计,但对于ASP.NET运行时中的性能关键型代码路径,这种差异实际上可能很重要。但是,他们可以使用一些变通方法,比如缓存每个处理程序类型的结果。有趣的是,ASMX Web服务(具有类似的性能特征)实际上使用WebMethod attributeEnableSession property来实现此目的。

与第三方.NET语言使用属性修饰类型相比,更有可能支持

  1. Implementing接口。由于ASP.NET被设计为语言不可知的,并且ASP.NET根据<%@ Page %> directiveEnableSessionState属性为实现上述接口的类型(可能在CodeDom的帮助下使用第三方语言)生成代码,因此使用接口而不是属性可能更有意义。

使用标记接口而不是属性的有说服力的理由是什么?

这仅仅是一种(过早的)吗?是优化还是框架设计中的一个小错误?(他们认为是reflection is a "big monster with red eyes"吗?)有什么想法?

EN

回答 6

Stack Overflow用户

发布于 2010-02-02 04:14:59

我通常避免使用“标记接口”,因为它们不允许您取消对派生类型的标记。但除此之外,下面是我见过的一些特定情况,其中标记接口比内置元数据支持更可取:

使用不支持批注或attributes.

  • Any context的语言对运行时性能敏感的situations.

  • Compatibility进行

  • ,其中感兴趣的代码可能无法访问泛型约束和泛型差异(通常是集合)的metadata.

  • Support。
票数 16
EN

Stack Overflow用户

发布于 2010-08-08 07:10:40

对于泛型类型,您可能希望在标记接口中使用相同的泛型参数。这不是通过一个属性可以实现的:

代码语言:javascript
复制
interface MyInterface<T> {}

class MyClass<T, U> : MyInterface<U> {}

class OtherClass<T, U> : MyInterface<IDictionary<U, T>> {}

这种接口对于将一种类型与另一种类型关联可能很有用。

标记接口的另一个很好的用法是当您想要创建kind of mixin

代码语言:javascript
复制
interface MyMixin {}

static class MyMixinMethods {
  public static void Method(this MyMixin self) {}
}

class MyClass : MyMixin {
}

acyclic visitor pattern也使用它们。术语“退化接口”有时也会被使用。

更新:

我不知道这个是否算数,但我已经用它们标记了post-compiler要处理的类。

票数 12
EN

Stack Overflow用户

发布于 2010-01-18 22:07:52

微软在制定API1.0时并没有严格遵循这些指导方针,因为这些指导方针是与框架一起演变的,而且他们直到改变.NET时才学习到一些规则已经为时已晚。

IIRC,你提到的例子属于BCL 1.0,这就可以解释它了。

这在Framework Design Guidelines中有解释。

也就是说,这本书还说“属性测试比类型检查的成本要高得多”(在Rico Mariani的侧栏中)。

它继续说,有时你需要标记接口来进行编译时检查,而这对于属性来说是不可能的。然而,我发现书中给出的例子(第88页)并不令人信服,所以我不会在这里重复。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2086451

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档