为什么接口不允许指定构造函数?

53

可能重复:
在接口中定义构造函数签名?

我知道在.Net中不能在接口中指定构造函数,但为什么不能呢?

对于我的当前项目,能够指定必须使用构造函数传递'engine'将非常有用,但由于不能使用构造函数,我不得不满足于在类上使用XML注释。

7个回答

93

接口描述行为。构造函数不是行为,对象如何构建是实现细节。


28
我认为这过于强调一个实现细节:在.NET中,构造函数只是在对象创建(在内存中分配)后立即调用的方法。它完全可以被定义为一种行为。当然,实现可以自由地声明其他构造函数,就像可以重载实现接口的方法一样。接口中的构造函数可能是一个很少使用的功能,但并不是无用的。 - EMP
1
我认为这个问题的重点是:既然它是这样构建的,那么最佳实践是什么?所以我认为答案是:使用抽象类,就像这个答案所说的那样:https://dev59.com/JXE85IYBdhLWcg3wYSdk#2804067 - Vince
1
一个公共构造函数显然是API的一部分。如果不是行为,那还能是什么呢? - Soundbytes

28
你会如何调用构造函数?当你使用接口时,通常会传递一个接口实例(或引用)。还要记住,如果一个类实现了一个接口,则派生类将继承该接口,但可能没有相同的构造函数集。
现在,我可以看到所谓的"静态接口"的用途,用于指定构造函数和其他本质上是静态成员以供泛型方法使用。有关更多信息,请参见我的博客文章(链接)中的这个想法。

1
我可以想到三个类似于接口的特性:(1)方法或属性的默认实现(注意,继承的接口将无法覆盖基础接口的实现);(2)允许相同的标识符有效地作为接口和静态类;(3)定义一个静态方法,在接口上调用“new”时使用。请注意,#2和#3将是语法糖,但我认为它们会使一些事情更清晰。如果.NET支持#1,则可以添加新的方法或属性而不会破坏现有的实现。 - supercat
@supercat:是的,我也考虑过1很长时间了 - 我相信微软也是如此。 Vance Morrison有一次采访谈到了这个问题。 - Jon Skeet
我很好奇关于#1正在做什么,我也想知道微软是否正在添加任何良好的方法来清理IDisposable当构造函数抛出异常时,或者(对于vb)是否会有一种自动杀死所有WithEvents订阅的方式。我看到了一些旧讨论新功能的链接;你有最新的吗? - supercat
@supercat:很抱歉,我不知道。我没有听说过任何相关的事情。 - Jon Skeet
@kingfrito_5005:你看了我链接的博客文章吗? - Jon Skeet
显示剩余4条评论

9
不,你不能在接口上有构造函数,原因已经被发布。然而,你可以在抽象类中有构造函数。例如,假设你有这个基类。
public abstract class ClassOne
{
    protected int _x;
    protected string _s;

    public ClassOne(int x, string s)
    {
        _x = x;
        _s = s;
    }        
}

注意没有不带参数的构造函数(默认构造函数),这意味着任何继承自ClassOne的类都必须调用具有2个参数的构造函数。

因此,以下代码是无效的并且不会编译。

public class ClassTwo : ClassOne
{
    public ClassTwo() 
    { }
}

然而,这是有效的并且可以编译。
public class ClassTwo : ClassOne
{
    public ClassTwo(int x, string s) : base(x, s)
    {  }
}

我想在这里指出,在C#中,您只能从一个基类继承。这意味着这可能不是特定情况下的正确解决方案,但值得考虑。
Tony.

1
由于类无法继承构造函数,我认为这只是一个部分解决方案,因为它要求子类以特殊的方式实现其构造函数调用,但不能保证子类具有相同签名的构造函数。 - kingfrito_5005

8

除了已经发布的其他原因外,还要记住一个类可以轻松实现多个接口; 那么应该使用哪个构造函数呢?


1
有一个完美的语法可以用于实现具有相同签名的接口方法,该语法也可以用于构造函数。 - Simon
我不确定我理解了你的意思(也许我没有):我的意思是,类A可以实现接口IAlpha,其构造函数没有参数;IBeta,其构造函数有一个参数;以及IGamma,其构造函数有两个参数:那么类A应该实现哪个构造函数? - M.Turrini
啊,这是唯一一个真正让我理解的答案。所有关于不能实例化接口的争论都让我感到困惑。“那又怎样?”。接口的意义在于声明任何假定实现接口的类必须实现某个函数集合。声称这样的类也应该实现一个构造函数,该构造函数需要特定的参数集合,听起来很合理。但是构造函数发生冲突的争论,确实存在问题。 - Jay
完全同意Jay的观点。虽然我认为通过接口强制构造函数签名并不是一个荒谬的想法,但需要更多的思考。 - Shravan
对于 .net 来说,禁止实现具有相同方法签名的接口并不难。事实上,它是否已经这样做了呢?如果没有,我认为它应该这样做,而不管构造函数的问题如何。 - kingfrito_5005

6
其他答案已经指出为什么在接口上声明构造函数是没有意义的。但从你的问题中,我猜想你可能正在寻找抽象工厂模式
举个例子,基于你的问题:你说你想要以某种方式声明必须传递一个“引擎”到构造函数中。你可以通过声明一个独立的构建服务接口来实现这一点:
public interface IGadgetFactory
{
   IGadget CreateGadget(Engine engine);
}

任何需要创建 IGadget 实例的代码,都可以使用 IGadgetFactory 实例来代替直接调用构造函数。

0

因为你不能实例化一个接口,所以构造函数没有意义。


6
抽象类如何有意义呢? - Indrek

0
除了这里提供的其他解释之外,无论如何您都必须发明一种新的语法来调用它们,因为如果在该行中范围内有两个或更多的实现:
Dim x as new IDoStuff()

哪个实现会被调用?


如果我在设计一种编程语言,我会允许接口命名一个静态方法供使用,这样上述语句就可以等同于例如 Dim X As IDoStuff = IDoStuff_Creator.CreateNew(); - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接