在编译时限制方法访问的最佳方法是什么?

本文关键字:方法 最佳 是什么 访问 编译 | 更新日期: 2023-09-27 17:53:22

假设我有一个Manager类

public class Manager {
   public Item Create() {
      ...
      return new Item(...);
   }
}

和Item类:

public class Item {
   [AllowCallBy(typeof(Manager))]
   public Item(...) {
   }
   ...
}

现在,我想使用最简单和最直接的方法在编译时分析属性(如AllowCallBy)并显示错误或警告。如果,在这种特殊情况下,一个非Manager类的类试图用new Item(...)实例化Item,我希望显示类似"不要直接实例化Item类,而是调用Manager. create(…)"的内容。

我想至少有一个系统:Roslyn, ReSharper, PostSharp或其他东西可以让我做到这一点,或者非常接近我想要达到的目标。谁能举个例子说明用什么和怎么用?

在编译时限制方法访问的最佳方法是什么?

这绝对是@Habib提到的代码气味(有人能链接到一个特定的吗?),但是没有一个更完整的例子,很难提供超出已经在评论中建议的替代方案。我鼓励你扩大你的样品或重新考虑你的设计。


但是,我可以提供一个我过去使用过的选项,尽管不是用于此目的。您可以将Item的构造函数标记为Obsolete:

public class Item {
   [Obsolete("Don't instantiate Item class directly, call Manager.Create(...) instead")]
   public Item(...) {
   }
   ...
}

然后在Manager类中,在调用构造函数时特别忽略此警告:

public class Manager {
   public Item Create() {
      ...
#pragma warning disable 618
      return new Item(...);
#pragma warning restore 618
   }
}
这样,每当有人试图在代码的其他地方创建自己的Item时,他们将得到一个2级CS0618警告,指示他们不应该使用该方法(注意,我没有说不能)与属性中输入的文本完全相同。如果将警告作为错误启用(针对所有警告或仅此警告),那么它将像您最初希望的那样是一个编译错误。

请注意,没有什么可以阻止其他人添加这些pragma语句来解决错误。然而,有了这个方法,开发人员不能说他们不知道他们不应该使用构造函数。

让我大吃一惊。PostSharp让你做你正在寻找的东西。简而言之,您将使用ComponentInternalAttribute来控制类型的可见性:

public class Item {
   [ComponentInternal(typeof(Manager))]
   public Item(...) {
   }
   ...
}

根据上面链接的他们的文档,试图在Manager之外调用Item的构造函数将产生编译时警告:

方法项目。由于[ComponentInternal]约束,不能从[其他方法]引用actor。

您可以通过更改属性的严重性级别使其为错误:

public class Item {
   [ComponentInternal(typeof(Manager), Severity = SeverityType.Error)]
   public Item(...) {
   }
   ...
}

有比当前方法更好的方法来实现你的目标,考虑到你实际上可以更改代码

例如,你可以将Item类的构造函数标记为私有,并向Item类添加一个静态工厂方法,该方法将负责创建类的实例。

另一种方法是将Item类移动到另一个程序集中,将其构造函数标记为内部,并实现另一个类(工厂),该类负责创建不同的Item对象。然后,您的类从其他程序集中可见,但不能直接实例化,因此强制代码用户使用提供的工厂。