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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/161231/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:14:01  来源:igfitidea点击:

How do you force constructor signatures and static methods?

提问by Sklivvz

Is there a way of forcing a (child) class to have constructors with particular signatures or particular static methods in C# or Java?

有没有办法强制(子)类在 C# 或 Java 中使用具有特定签名或特定静态方法的构造函数?

You can't obviously use interfaces for this, and I know that it will have a limited usage. One instance in which I do find it useful is when you want to enforce some design guideline, for example:

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

Exceptions
They should all have the four canonical constructors, but there is no way to enforce it. You have to rely on a tool like FxCop (C# case) to catch these.

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

Operators
There is no contract that specifies that two classes can be summed (with operator+ in C#)

运算符
没有约定可以对两个类进行求和(在 C# 中使用运算符 +)

Is there any design pattern to work around this limitation? What construct could be added to the languageto overcome this limitation in future versions of C# or Java?

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

采纳答案by Marc Gravell

Not enforced at compile-time, but I have spent a lot of time looking at similar issues; a generic-enabled maths library, and an efficient (non-default) ctor API are both avaiable in MiscUtil. However, these are only checked at first-usage at runtime. In reality this isn't a big problem - your unit tests should find any missing operator / ctor very quickly. But it works, and very quickly...

未在编译时强制执行,但我花了很多时间研究类似的问题;一个启用通用,数学库,以及一个有效的(非默认)构造函数API在两种缴费MiscUtil。但是,这些仅在运行时首次使用时进行检查。实际上,这不是什么大问题——您的单元测试应该很快找到任何丢失的操作符/构造函数。但它有效,而且很快......

回答by Jon Skeet

Using generics you can force a type argument to have a parameterless constructor - but that's about the limit of it.

使用泛型你可以强制一个类型参数有一个无参数的构造函数——但这就是它的限制。

Other than in generics, it would be tricky to actually usethese restrictions even if they existed, but it could sometimes be useful for type parameters/arguments. Allowing static members in interfaces (or possibly static interfaces) could likewise help with the "generic numeric operator" issue.

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

I wrote about thisa little while ago when facing a similar problem.

写了一篇关于这个面临着类似的问题的时候,而前一点点。

回答by TToni

The problem in the language is that static methods are really second class citizens (A constructor is also a kind of static method, because you don't need an instance to start with).

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

Static methods are just global methods with a namespace, they don't really "belong" to the class they are defined in (OK, they have access to private (static) methods in the class, but that's about it).

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

The problem on the compiler level is that without a class instance you don't have a virtual function table, which means you cannot use all the inheritance and polymorphism stuff.

编译器级别的问题是,如果没有类实例,您就没有虚函数表,这意味着您不能使用所有继承和多态性的东西。

I think one could make it work by adding a global/static virtual table for each class but if it hasn't been done yet, there's probably a good reason for it.

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

回答by jop

Force Constructors

力构造器

You can't. The closest that you can come is make the default constructor private and then provide a constructor that has parameters. But it still has loopholes.

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

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
}

回答by ZeroBugBounce

Well, I know from the wording of your question you are looking for compile-time enforcement. Unless someone else has a brilliant suggestion/hack that will allow you to do this the way you are implying the compiler should, I would suggest that you could write a custom MSbuild task that did this. An AOP framework like PostSharp might help you accomplish this at comiple-time by piggy backing on it's build task model.

好吧,我从您的问题的措辞中知道您正在寻找编译时强制执行。除非其他人有一个绝妙的建议/技巧可以让您按照您暗示编译器应该的方式执行此操作,否则我建议您可以编写一个自定义的 MSbuild 任务来执行此操作。像 PostSharp 这样的 AOP 框架可能会帮助您在编译时通过支持它的构建任务模型来完成此任务。

But what is wrong with code analysis or run-time enforcement? Maybe it's just preference and I respect that, but I personally have no issues with having CA/FXCop check these things... and if you really want to force downstream implementers of your classes to have constructor signatures, you can always add rules run-time checking in the base class constructor using reflection.

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

Richard

理查德

回答by jrudolph

You could use the Factory pattern.

您可以使用工厂模式。

interface Fruit{}

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

   Cocktail mixFruits(F f1,F f2);
}

You could then create classes for any type of Fruit

然后你可以为任何类型的水果创建类

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
   }
}

This does not enforce that you can't create instance in another way than by using the Factory but at least you can specify which methods you would request from a Factory.

这并不强制您不能以除使用工厂之外的其他方式创建实例,但至少您可以指定您将从工厂请求哪些方法。

回答by Sklivvz

Here is I would solve it if I were a language designer.

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

Allow interfaces to include static methods, operators and constructors.

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

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

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

Don't allow the corresponding new IFoo(someInt)or IFoo.Bar()

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

Allow constructors to be inherited (just like static methods).

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

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) {};
}

Allow the programmer to cast to interfacesand check, if necessary, at run time if the cast is semanticallyvalid even if the class does not specify explicitly.

允许程序员强制转换为接口,并在必要时在运行时检查强制转换在语义上是否有效,即使类没有明确指定。

ISummable PassedFirstGrade = (ISummable) 10; 

回答by Jonathan C Dickinson

Unfortunately you can't in C#. Here is a punch at it though:

不幸的是你不能在 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();
}

回答by marcj

I'm unsure as to what you are trying to achieve, can you please elaborate? The only reason for forcing a specific constructor or static method accross different classes is to try and execute them dynamically at run time, is this correct?

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

A constructor is intended to be specific to a particular class, as it is intended to initialise the specific needs of the class. As I understand it, the reason you would want to enforce something in a class hierarchy or interface, is that it is an activity/operation relevant to the process being performed, but may vary in different circumstances. I believe this is the intended benefit of polymorphism, which you can't achieve using static methods.

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

It would also require knowing the specific type of the class you wanted to call the static method for, which would break all of the polymorphic hiding of differences in behaviour that the interface or abstract class is trying to achieve.

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

If the behaviour being represented by the constructor is intended to be part of the contract between the client of these classes then I would add it explicitly to the interface.

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

If a hierarchy of classes have similar initialisation requirements then I would use an abstract base class, however it should be up to the inheriting classes how they find the parameter for that constructor, which may include exposing a similar or identical constructor.

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

If this is intended to allow you to create different instances at runtime, then I would recommend using a static method on an abstract base class which knows the different needs of all of the concrete classes (you could use dependency injection for this).

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