很奇怪,这是我第一次遇到这个问题,但是:

如何在c#接口中定义构造函数?

编辑 有些人想要一个例子(这是一个自由时间项目,所以是的,这是一个游戏)

IDrawable +更新 +画

为了能够更新(检查屏幕边缘等)和绘制本身,它总是需要一个GraphicsDeviceManager。我想确保对象有一个指向它的引用。这将属于构造函数。

现在我把这个写下来了,我想我在这里实现的是IObservable GraphicsDeviceManager应该采用IDrawable。 似乎不是我没有理解XNA框架,就是这个框架没有考虑得很好。

编辑 我在接口上下文中对构造函数的定义似乎有些混乱。接口确实不能被实例化,因此不需要构造函数。我想定义的是构造函数的签名。就像接口可以定义某个方法的签名一样,接口也可以定义构造函数的签名。


当前回答

如前所述,在接口上不能有构造函数。但是,由于这是7年后谷歌中排名如此高的结果,我想我应该在这里补充一下——具体来说,是为了展示如何将抽象基类与现有的接口一起使用,并且可能会减少将来在类似情况下所需的重构量。在一些评论中已经暗示了这个概念,但我认为值得展示如何实际做到这一点。

到目前为止你的主界面是这样的:

public interface IDrawable
{
    void Update();
    void Draw();
}

现在用要强制的构造函数创建一个抽象类。实际上,自从你写你最初的问题以来,它就已经可用了,我们可以在这里稍微花点时间,在这种情况下使用泛型,这样我们就可以适应其他可能需要相同功能但有不同构造函数要求的接口:

public abstract class MustInitialize<T>
{
    public MustInitialize(T parameters)
    {

    }
}

现在你需要创建一个继承IDrawable接口和MustInitialize抽象类的新类:

public class Drawable : MustInitialize<GraphicsDeviceManager>, IDrawable
{
    GraphicsDeviceManager _graphicsDeviceManager;

    public Drawable(GraphicsDeviceManager graphicsDeviceManager)
        : base (graphicsDeviceManager)
    {
        _graphicsDeviceManager = graphicsDeviceManager;
    }

    public void Update()
    {
        //use _graphicsDeviceManager here to do whatever
    }

    public void Draw()
    {
        //use _graphicsDeviceManager here to do whatever
    }
}

然后只需创建一个Drawable实例,就可以了:

IDrawable drawableService = new Drawable(myGraphicsDeviceManager);

这里很酷的是,我们创建的新Drawable类仍然像我们期望的IDrawable一样。

如果需要向MustInitialize构造函数传递多个参数,可以创建一个类,为需要传递的所有字段定义属性。

其他回答

虽然您不能在接口中定义构造函数签名,但我觉得值得一提的是,这可能是考虑抽象类的一个地方。抽象类可以以与接口相同的方式定义未实现的(抽象的)方法签名,但也可以有实现的(具体的)方法和构造函数。

缺点是,因为它是一种类类型,所以它不能用于接口可以使用的任何多继承类型场景。

你不能。它偶尔会让人感到痛苦,但无论如何,使用正常的技术都无法调用它。

在一篇博客文章中,我建议静态接口只能在泛型类型约束中使用——但在我看来,它真的很方便。

如果你可以在一个接口中定义一个构造函数,那么你在派生类时就会遇到麻烦:

public class Foo : IParameterlessConstructor
{
    public Foo() // As per the interface
    {
    }
}

public class Bar : Foo
{
    // Yikes! We now don't have a parameterless constructor...
    public Bar(int x)
    {
    }
}

通用工厂方法似乎仍然是理想的。您将知道工厂需要一个形参,而这些形参恰好被传递给正在实例化的对象的构造函数。

注意,这只是经过语法验证的伪代码,这里可能忽略了一个运行时警告:

public interface IDrawableFactory
{
    TDrawable GetDrawingObject<TDrawable>(GraphicsDeviceManager graphicsDeviceManager) 
              where TDrawable: class, IDrawable, new();
}

public class DrawableFactory : IDrawableFactory
{
    public TDrawable GetDrawingObject<TDrawable>(GraphicsDeviceManager graphicsDeviceManager) 
                     where TDrawable : class, IDrawable, new()
    {
        return (TDrawable) Activator
                .CreateInstance(typeof(TDrawable), 
                                graphicsDeviceManager);
    }

}

public class Draw : IDrawable
{
 //stub
}

public class Update : IDrawable {
    private readonly GraphicsDeviceManager _graphicsDeviceManager;

    public Update() { throw new NotImplementedException(); }

    public Update(GraphicsDeviceManager graphicsDeviceManager)
    {
        _graphicsDeviceManager = graphicsDeviceManager;
    }
}

public interface IDrawable
{
    //stub
}
public class GraphicsDeviceManager
{
    //stub
}

一个可能用法的例子:

    public void DoSomething()
    {
        var myUpdateObject = GetDrawingObject<Update>(new GraphicsDeviceManager());
        var myDrawObject = GetDrawingObject<Draw>(null);
    }

当然,您只需要通过工厂创建实例来保证始终有一个适当初始化的对象。也许使用像AutoFac这样的依赖注入框架会有意义;Update()可以向IoC容器“请求”一个新的GraphicsDeviceManager对象。

一个非常晚的贡献,展示了接口构造函数的另一个问题。(我选择这个问题是因为它对问题有最清晰的阐述)。假设我们有:

interface IPerson
{
    IPerson(string name);
}

interface ICustomer
{
    ICustomer(DateTime registrationDate);
}

class Person : IPerson, ICustomer
{
    Person(string name) { }
    Person(DateTime registrationDate) { }
}

其中,按照约定,“接口构造函数”的实现被类型名替换。

现在做一个例子:

ICustomer a = new Person("Ernie");

我们可以说客户遵守了合同吗?

还有这个呢:

interface ICustomer
{
    ICustomer(string address);
}

你不能。

接口定义了由其他对象实现的契约,因此不需要初始化状态。

如果需要初始化某些状态,则应该考虑使用抽象基类。