你如何强制构造函数签名和静态方法?

是否有一种方法可以强制(子)类在C#或Java中使用具有特定签名或特定静态方法的构造函数?

你显然不能使用接口,我知道它的用途有限。 我发现它有用的一个实例是当你想强制执行一些设计指南时,例如:

例外
它们应该都有四个规范构造函数,但是没有办法强制执行它。 你必须依靠像FxCop(C#case)之类的工具来捕获它们。

运营商
没有合同规定可以对两个类求和(在C#中使用operator +)

是否有任何设计模式可以解决此限制? 可以在语言中添加什么构造来克服C#或Java的未来版本中的这种限制?

在编译时没有强制执行,但我花了很多时间研究类似的问题; 一个支持通用的数学库 ,以及一个有效的(非默认的)ctor API都可以在MiscUtil中使用 。 但是,这些仅在运行时首次使用时进行检查。 实际上这不是一个大问题 – 您的unit testing应该很快找到任何缺少的操作符/ ctor。 但它很有效,但很快……

使用generics,您可以强制类型参数具有无参数构造函数 – 但这是关于它的限制。

除了generics之外,实际使用这些限制即使它们存在也很棘手,但它有时对类型参数/参数有用。 允许接口(或可能是静态接口)中的静态成员同样可以帮助解决“通用数字运算符”问题。

我不久前在遇到类似问题时写过这篇文章。

您可以使用Factory模式。

interface Fruit{} interface FruitFactory{ F newFruit(String color,double weight); Cocktail mixFruits(F f1,F f2); } 

然后,您可以为任何类型的Fruit创建类

 class Apple implements Fruit{} class AppleFactory implements FruitFactory{ public Apple newFruit(String color, double weight){ // create an instance } public Cocktail mixFruits(Apple f1,Apple f2){ // implementation } } 

这并不强制您不能以不同于使用Factory的方式创建实例,但至少可以指定要从Factory请求的方法。

强制构造者

你不能。 最接近的是将默认构造函数设为私有,然后提供具有参数的构造函数。 但它仍有漏洞。

 class Base { private Base() { } public Base(int x) {} } class Derived : Base { //public Derived() { } won't compile because Base() is private public Derived(int x) :base(x) {} public Derived() : base (0) {} // still works because you are giving a value to base } 

语言中的问题是静态方法实际上是二级公民(构造函数也是一种静态方法,因为你不需要一个实例来开始)。

静态方法只是具有命名空间的全局方法,它们并不真正“属于”它们所定义的类(好吧,它们可以访问类中的私有(静态)方法,但这就是它)。

编译器级别的问题是没有类实例,你没有虚函数表,这意味着你不能使用所有的inheritance和多态。

我认为可以通过为每个类添加一个全局/静态虚拟表来使其工作,但如果还没有完成,那么可能有一个很好的理由。

如果我是语言设计师,我会解决这个问题。

允许接口包含静态方法,运算符和构造函数。

 interface IFoo { IFoo(int gottaHaveThis); static Bar(); } interface ISummable { operator+(ISummable a, ISummable b); } 

不要允许相应的new IFoo(someInt)IFoo.Bar()

允许inheritance构造函数(就像静态方法一样)。

 class Foo: IFoo { Foo(int gottaHaveThis) {}; static Bar() {}; } class SonOfFoo: Foo { // SonOfFoo(int gottaHaveThis): base(gottaHaveThis); is implicitly defined } class DaughterOfFoo: Foo { DaughhterOfFoo (int gottaHaveThis) {}; } 

如果转换在语义上有效,即使该类未明确指定,也允许程序员转换为接口并在运行时检查(如有必要)。

 ISummable PassedFirstGrade = (ISummable) 10; 

不幸的是你不能在C#中。 尽管如此:

 class Program { static void Main(string[] args) { Console.WriteLine(Foo.Instance.GetHelloWorld()); Console.ReadLine(); } } public class Foo : FooStaticContract { public Foo() // Non-static ctor. { } internal Foo(bool st) // Overloaded, parameter not used. { } public override string GetHelloWorld() { return "Hello World"; } } public class FooFactory : IStaticContractFactory { #region StaticContractFactory Members public Foo CreateInstance() { return new Foo(true); // Call static ctor. } #endregion } public interface IStaticContractFactory { T CreateInstance(); } public abstract class StaticContract where Factory : IStaticContractFactory, new() where T : class { private static Factory _factory = new Factory(); private static T _instance; ///  /// Gets an instance of this class. ///  public static T Instance { get { // Scary. if (Interlocked.CompareExchange(ref _instance, null, null) == null) { T instance = _factory.CreateInstance(); Interlocked.CompareExchange(ref _instance, instance, null); } return _instance; } } } public abstract class FooStaticContract : StaticContract where Factory : IStaticContractFactory, new() { public abstract string GetHelloWorld(); } 

好吧,我从你的问题的措辞中知道你正在寻找编译时执行。 除非其他人有一个很好的建议/黑客,这将允许你按照你暗示编译器的方式这样做,我建议你可以写一个自定义的MSbuild任务来做到这一点。 像PostSharp这样的AOP框架可以通过小心支持它的构建任务模型来帮助你在comiple-time完成这个任务。

但是代码分析或运行时执行有什么问题? 也许这只是偏好,我尊重这一点,但我个人对CA / FXCop检查这些内容没有任何问题……如果你真的想强迫你的类的下游实现者拥有构造函数签名,你可以随时添加规则run-使用reflection在基类构造函数中检查时间。

理查德

我不确定你想要达到的目标,请你详细说明一下吗? 在不同的类中强制使用特定构造函数或静态方法的唯一原因是尝试在运行时动态执行它们,这是正确的吗?

构造函数旨在特定于特定类,因为它旨在初始化类的特定需求。 据我了解,您希望在类层次结构或接口中强制执行某些操作的原因是它是与正在执行的进程相关的活动/操作,但在不同情况下可能会有所不同。 我相信这是多态性的预期好处,使用静态方法无法实现。

它还需要知道您想要调用静态方法的类的特定类型,这将破坏接口或抽象类试图实现的行为差异的所有多态隐藏。

如果构造函数表示的行为旨在成为这些类的客户端之间的契约的一部分,那么我将明确地将它添加到接口。

如果类的层次结构具有相似的初始化要求,那么我将使用抽象基类,但是它应该如何为inheritance类找到该构造函数的参数,这可能包括暴露类似或相同的构造函数。

如果这是为了允许您在运行时创建不同的实例,那么我建议在抽象基类上使用静态方法,它知道所有具体类的不同需求(您可以使用dependency injection)。