有没有办法强制(子)类在C#或Java中使用特定签名或特定静态方法的构造函数?
你显然不能使用接口,我知道它的用途有限。我发现它有用的一个实例是当你想强制执行一些设计指南时,例如:
例外
它们应该都有四个规范构造函数,但是没有办法强制执行它。你必须依靠像FxCop(C#case)这样的工具来捕捉它们。
算
没有合同规定可以对两个类求和(使用C#中的operator +)
是否有任何设计模式可以解决此限制? 可以在语言中添加什么构造来克服未来版本的C#或Java中的这种限制?
答案 0 :(得分:10)
使用泛型可以强制类型参数具有无参数构造函数 - 但这是关于它的限制。
除了泛型之外,即使它们存在,实际上使用这些限制也是棘手的,但它有时对类型参数/参数有用。允许接口(或可能是静态接口)中的静态成员同样可以帮助解决“通用数字运算符”问题。
我wrote about this不久前遇到类似的问题。
答案 1 :(得分:8)
在编译时没有强制执行,但我花了很多时间研究类似的问题;一个generic-enabled maths library和一个有效的(非默认)ctor API都可以在MiscUtil中使用。但是,这些仅在运行时首次使用时进行检查。实际上这不是一个大问题 - 您的单元测试应该很快找到任何缺少的操作符/ ctor。但它很有效,而且很快......
答案 2 :(得分:6)
您可以使用工厂模式。
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的方式创建实例,但至少可以指定您从工厂请求的方法。
答案 3 :(得分:4)
你做不到。您最接近的是使默认构造函数为private,然后提供具有参数的构造函数。但它仍然存在漏洞。
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
}
答案 4 :(得分:1)
语言中的问题是静态方法实际上是二级公民(构造函数也是一种静态方法,因为你不需要一个实例来开始)。
静态方法只是具有命名空间的全局方法,它们并不真正“属于”它们所定义的类(好吧,它们可以访问类中的私有(静态)方法,但这就是它)。
编译器级别的问题是没有类实例你没有虚函数表,这意味着你不能使用所有的继承和多态。
我认为可以通过为每个类添加一个全局/静态虚拟表来使其工作,但如果尚未完成,则可能有充分的理由。
答案 5 :(得分:1)
如果我是语言设计师,我会解决这个问题。
允许接口包含静态方法,运算符和构造函数。
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;
答案 6 :(得分:1)
不幸的是你不能在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();
}
答案 7 :(得分:0)
嗯,我从你问题的措辞中知道你正在寻找编译时的执行。除非其他人有一个很好的建议/黑客,这将允许你按照你暗示编译器的方式这样做,我建议你可以写一个自定义的MSbuild任务来做到这一点。像PostSharp这样的AOP框架可以通过小心支持它的构建任务模型来帮助你在comiple-time完成这个任务。
但是代码分析或运行时执行有什么问题?也许这只是偏好,我尊重这一点,但我个人对CA / FXCop检查这些东西没有任何问题......如果你真的想迫使你的类的下游实现者拥有构造函数签名,你可以随时添加规则run-使用反射在基类构造函数中检查时间。
理查德
答案 8 :(得分:0)
我不确定你想要达到的目标,请详细说明一下?在不同的类中强制使用特定构造函数或静态方法的唯一原因是尝试在运行时动态执行它们,这是正确的吗?
构造函数旨在特定于特定类,因为它旨在初始化类的特定需求。据我所知,您希望在类层次结构或接口中强制执行某些操作的原因是它是与正在执行的进程相关的活动/操作,但在不同情况下可能会有所不同。我相信这是多态性的预期好处,使用静态方法无法实现。
还需要知道要调用静态方法的类的特定类型,这将破坏接口或抽象类试图实现的行为差异的所有多态隐藏。
如果构造函数表示的行为是这些类的客户端之间的契约的一部分,那么我会将它显式添加到接口。
如果类的层次结构具有相似的初始化要求,那么我将使用抽象基类,但是它应该如何为继承类找到该构造函数的参数,这可能包括暴露类似或相同的构造函数。 / p>
如果这是为了允许你在运行时创建不同的实例,那么我建议在抽象基类上使用静态方法,它知道所有具体类的不同需求(你可以使用依赖注入)