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

时间:2020-03-06 15:00:51  来源:igfitidea点击:

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

我们显然不能为此使用接口,而且我知道它的用法会受到限制。我确实认为有用的一个实例是我们想要实施一些设计准则时,例如:

例外情况
它们都应该具有四个规范的构造函数,但是没有办法强制执行它。我们必须依靠FxCop(Ccase)之类的工具才能捕获这些信息。

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

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

解决方案

使用泛型,我们可以强制类型参数具有无参数的构造函数,但这仅是其极限。

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

不久前,我遇到类似问题时就写了这个。

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

静态方法只是带有命名空间的全局方法,它们实际上并不"属于"它们在其中定义的类(好的,它们可以访问该类中的私有(静态)方法,仅此而已)。

编译器级别的问题是,没有类实例,我们将没有虚拟函数表,这意味着我们无法使用所有继承和多态性东西。

我认为可以通过为每个类添加一个全局/静态虚拟表来使其工作,但是如果尚未完成,则可能有充分的理由。

部队建设者

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

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
}

好吧,从我们所提问题的措辞中我知道,我们正在寻找编译时强制执行的问题。除非其他人有出色的建议/技巧,使我们能够按照暗示编译器的方式执行此操作,否则我建议我们可以编写一个自定义MSbuild任务来执行此操作。诸如PostSharp之类的AOP框架可以通过支持其构建任务模型来在复杂的时间内完成此任务。

但是代码分析或者运行时强制执行有什么问题?也许这只是偏爱而已,我对此表示尊重,但我个人认为让CA / FXCop检查这些事情没有问题...而且,如果我们真的要强制类的下游实现者具有构造函数签名,则可以随时添加运行规则-在使用反射的基类构造函数中进行时间检查。

理查德

我们可以使用Factory模式。

interface Fruit{}

interface FruitFactory<F extends Fruit>{
   F newFruit(String color,double weight);

   Cocktail mixFruits(F f1,F f2);
}

然后,我们可以为任何类型的水果创建类

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

这并不意味着我们不能使用使用Factory以外的其他方式来创建实例,但至少可以指定要从Factory请求的方法。

如果我是语言设计师,这就是我要解决的问题。

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

interface IFoo  
{  
  IFoo(int gottaHaveThis);  
  static Bar();  
}

interface ISummable
{
      operator+(ISummable a, ISummable b);
}

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

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

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<FooFactory>
{
    public Foo() // Non-static ctor.
    {
    }

    internal Foo(bool st) // Overloaded, parameter not used.
    {
    }

    public override string GetHelloWorld()
    {
        return "Hello World";
    }
}

public class FooFactory : IStaticContractFactory<Foo>
{
    #region StaticContractFactory<Foo> Members

    public Foo CreateInstance()
    {
        return new Foo(true); // Call static ctor.
    }

    #endregion
}

public interface IStaticContractFactory<T>
{
    T CreateInstance();
}

public abstract class StaticContract<T, Factory>
    where Factory : IStaticContractFactory<T>, new() 
    where T : class
{
    private static Factory _factory = new Factory();

    private static T _instance;
    /// <summary>
    /// Gets an instance of this class. 
    /// </summary>
    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<Factory>
    : StaticContract<Foo, Factory>
    where Factory : IStaticContractFactory<Foo>, new() 
{
    public abstract string GetHelloWorld();
}

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

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

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

如果构造函数表示的行为旨在成为这些类的客户端之间的合同的一部分,则可以将其显式添加到接口中。

如果类的层次结构具有相似的初始化要求,那么我将使用抽象基类,但是,继承类应如何确定该构造函数的参数,这可能包括公开相似或者相同的构造函数。

如果这样做是为了允许我们在运行时创建不同的实例,那么我建议在抽象基类上使用静态方法,该基类知道所有具体类的不同需求(我们可以为此使用依赖注入)。

在编译时没有强制执行,但是我花了很多时间研究类似的问题。在MiscUtil中都可以使用启用了泛型的数学库以及有效的(非默认)ctor API。但是,这些仅在运行时首次使用时进行检查。实际上,这不是一个大问题,单元测试应该很快找到任何丢失的运算符/ ctor。但这很快并且有效。。。。。。。。。。。。。。。。。。。。。。。。。。。