如何强制构造函数签名和静态方法?
是否有办法强制(子)类在 C# 或 Java 中具有具有特定签名或特定静态方法的构造函数?
显然,您不能为此使用接口,而且我知道它会有用途有限。 我确实发现它很有用的一个例子是当您想要强制执行某些设计准则时,例如:
异常
它们都应该具有四个规范构造函数,但没有办法强制执行。 您必须依靠像 FxCop(C# 情况)这样的工具来捕获这些。
运营商
没有合同指定可以对两个类求和(在 C# 中使用运算符+)
是否有任何设计模式可以解决此限制? 可以在语言中添加什么结构来克服 C# 或 Java 未来版本中的这一限制?
Is there a way of forcing a (child) class to have constructors with particular signatures or particular static methods in C# or 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.
Operators
There is no contract that specifies that two classes can be summed (with operator+ in C#)
Is there any design pattern to work around this limitation?
What construct could be added to the language to overcome this limitation in future versions of C# or Java?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
使用泛型,您可以强制类型参数具有无参数构造函数 - 但这就是它的限制。
除了泛型之外,即使存在这些限制,实际使用也会很棘手,但有时它对于类型参数/参数可能很有用。 在接口(或可能是静态接口)中允许静态成员同样可以帮助解决“通用数字运算符”问题。
我 写过这个 不久前遇到类似的问题。
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 use these 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 this a little while ago when facing a similar problem.
在编译时没有强制执行,但我花了很多时间研究类似的问题; 一个支持通用的数学库,以及一个高效的(非-default) ctor API 均在 MiscUtil 中提供。 但是,这些仅在运行时首次使用时检查。 实际上这不是一个大问题 - 你的单元测试应该很快找到任何丢失的操作符/构造函数。 但它确实有效,而且很快......
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...
您可以使用工厂模式。
然后,您可以为任何类型的 Fruit 创建类。
这并不强制您不能使用工厂以外的其他方式创建实例,但至少您可以指定从工厂请求哪些方法。
You could use the Factory pattern.
You could then create classes for any type of Fruit
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.
强制构造函数
你不能。 最接近的方法是将默认构造函数设为私有,然后提供一个具有参数的构造函数。 但它仍然存在漏洞。
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.
该语言的问题在于静态方法实际上是二等公民(构造函数也是一种静态方法,因为您不需要实例来启动)。
静态方法只是具有命名空间的全局方法,它们并不真正“属于”它们定义的类(好吧,它们可以访问类中的私有(静态)方法,但仅此而已)。
编译器级别的问题是,如果没有类实例,就没有虚拟函数表,这意味着您无法使用所有继承和多态性内容。
我认为可以通过为每个类添加一个全局/静态虚拟表来使其工作,但如果尚未完成,可能有一个很好的理由。
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.
如果我是一名语言设计师,我会解决这个问题。
允许接口包含静态方法、运算符和构造函数。
不允许相应的
new IFoo(someInt)
或IFoo.Bar()
允许继承构造函数(就像静态方法一样)。
允许程序员强制转换为接口,并在必要时在运行时检查是否即使类没有明确指定,强制转换在语义上也是有效的。
Here is I would solve it if I were a language designer.
Allow interfaces to include static methods, operators and constructors.
Don't allow the corresponding
new IFoo(someInt)
orIFoo.Bar()
Allow constructors to be inherited (just like static methods).
Allow the programmer to cast to interfaces and check, if necessary, at run time if the cast is semantically valid even if the class does not specify explicitly.
不幸的是你不能在 C# 中。 不过,这里有一个重拳:
Unfortunately you can't in C#. Here is a punch at it though:
好吧,我从你问题的措辞中知道你正在寻找编译时执行。 除非其他人有一个出色的建议/黑客允许您按照编译器暗示的方式执行此操作,否则我建议您可以编写一个自定义的 MSbuild 任务来执行此操作。 像 PostSharp 这样的 AOP 框架可能会通过其构建任务模型来帮助您在编译时完成此任务。
但是代码分析或运行时执行有什么问题呢? 也许这只是偏好,我尊重这一点,但我个人对让 CA/FXCop 检查这些东西没有任何问题......如果你真的想强制你的类的下游实现者具有构造函数签名,你可以随时添加规则运行-使用反射检查基类构造函数的时间。
理查德
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.
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.
Richard
我不确定你想要达到什么目的,你能详细说明一下吗? 在不同的类中强制使用特定的构造函数或静态方法的唯一原因是尝试在运行时动态执行它们,这是正确的吗?
构造函数旨在特定于特定类,因为它旨在初始化类的特定需求。 据我了解,您想要在类层次结构或接口中强制执行某些内容的原因是,它是与正在执行的流程相关的活动/操作,但在不同的情况下可能会有所不同。 我相信这是多态性的预期好处,这是使用静态方法无法实现的。
它还需要知道要为其调用静态方法的类的特定类型,这将打破接口或抽象类试图实现的行为差异的所有多态隐藏。
如果构造函数所表示的行为旨在成为这些类的客户端之间契约的一部分,那么我会将其显式添加到接口中。
如果类的层次结构具有类似的初始化要求,那么我将使用抽象基类,但是应该由继承类决定如何找到该构造函数的参数,其中可能包括公开类似或相同的构造函数。
如果这是为了允许您在运行时创建不同的实例,那么我建议在抽象基类上使用静态方法,该方法知道所有具体类的不同需求(您可以为此使用依赖注入)。
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).