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

时间:2015-06-03 14:56:10

标签: c# .net resharper roslyn

我们说我有一个经理类

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

我有一个Item类:

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

现在,我想使用最简单,最直接的方法在编译时分析AllowCallBy等属性并显示错误或警告。如果在这种特殊情况下,Manager类以外的类尝试使用Item实例化new Item(...),我想显示类似于"不要直接实例化Item类,调用Manager 。而不是创建(...)"。

我认为至少有一个系统:Roslyn,ReSharper,PostSharp或者别的东西可以让我这样做,或者与我想要达到的非常接近的东西。有人可以举例说明使用什么以及如何使用它吗?

3 个答案:

答案 0 :(得分:3)

@Habib提到这肯定是code smell(有人可以链接到特定的吗?),但如果没有更完整的例子,除了评论中已经提出的建议之外,很难提供替代方案。我鼓励您扩展样本或重新考虑您的设计。

但是,我可以提供过去曾用过的一个选项,但不是为了这个目的。您可以将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时,他们就会得到level 2 CS0618 warning,表明他们不应使用该方法(请注意,我并没有说不能),而且确切地说是在属性中输入的文本。如果启用了warnings as errors(对于所有警告或只是这个警告),那么它将是您最初想要的编译错误。

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

答案 1 :(得分:1)

我很惊讶。 PostSharp lets you do exactly what you're looking for。简而言之,您可以使用ComponentInternalAttribute来控制类型的可见性:

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

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

  

由于[ComponentInternal]约束,无法从 [其他方法] 引用方法Item.ctor。

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

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

答案 2 :(得分:0)

有更好的方法来实现您的目标,而不是您当前的方法,,因为您可以实际更改该代码

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

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