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

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

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

IDrawable +更新 +画

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

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

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


当前回答

我用下面的图案使它防弹。

A developer who derives his class from the base can't accidentally create a public accessible constructor The final class developer are forced to go through the common create method Everything is type-safe, no castings are required It's 100% flexible and can be reused everywhere, where you can define your own base class. Try it out you can't break it without making modifications to the base classes (except if you define an obsolete flag without error flag set to true, but even then you end up with a warning) public abstract class Base<TSelf, TParameter> where TSelf : Base<TSelf, TParameter>, new() { protected const string FactoryMessage = "Use YourClass.Create(...) instead"; public static TSelf Create(TParameter parameter) { var me = new TSelf(); me.Initialize(parameter); return me; } [Obsolete(FactoryMessage, true)] protected Base() { } protected virtual void Initialize(TParameter parameter) { } } public abstract class BaseWithConfig<TSelf, TConfig>: Base<TSelf, TConfig> where TSelf : BaseWithConfig<TSelf, TConfig>, new() { public TConfig Config { get; private set; } [Obsolete(FactoryMessage, true)] protected BaseWithConfig() { } protected override void Initialize(TConfig parameter) { this.Config = parameter; } } public class MyService : BaseWithConfig<MyService, (string UserName, string Password)> { [Obsolete(FactoryMessage, true)] public MyService() { } } public class Person : Base<Person, (string FirstName, string LastName)> { [Obsolete(FactoryMessage,true)] public Person() { } protected override void Initialize((string FirstName, string LastName) parameter) { this.FirstName = parameter.FirstName; this.LastName = parameter.LastName; } public string LastName { get; private set; } public string FirstName { get; private set; } } [Test] public void FactoryTest() { var notInitilaizedPerson = new Person(); // doesn't compile because of the obsolete attribute. Person max = Person.Create(("Max", "Mustermann")); Assert.AreEqual("Max",max.FirstName); var service = MyService.Create(("MyUser", "MyPassword")); Assert.AreEqual("MyUser", service.Config.UserName); }

编辑: 这是一个基于你的绘图示例的例子,它甚至强制了接口抽象

        public abstract class BaseWithAbstraction<TSelf, TInterface, TParameter>
        where TSelf : BaseWithAbstraction<TSelf, TInterface, TParameter>, TInterface, new()
    {
        [Obsolete(FactoryMessage, true)]
        protected BaseWithAbstraction()
        {
        }

        protected const string FactoryMessage = "Use YourClass.Create(...) instead";
        public static TInterface Create(TParameter parameter)
        {
            var me = new TSelf();
            me.Initialize(parameter);

            return me;
        }

        protected virtual void Initialize(TParameter parameter)
        {

        }
    }



    public abstract class BaseWithParameter<TSelf, TInterface, TParameter> : BaseWithAbstraction<TSelf, TInterface, TParameter>
        where TSelf : BaseWithParameter<TSelf, TInterface, TParameter>, TInterface, new()
    {
        protected TParameter Parameter { get; private set; }

        [Obsolete(FactoryMessage, true)]
        protected BaseWithParameter()
        {
        }
        protected sealed override void Initialize(TParameter parameter)
        {
            this.Parameter = parameter;
            this.OnAfterInitialize(parameter);
        }

        protected virtual void OnAfterInitialize(TParameter parameter)
        {
        }
    }


    public class GraphicsDeviceManager
    {

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

    internal abstract class Drawable<TSelf> : BaseWithParameter<TSelf, IDrawable, GraphicsDeviceManager>, IDrawable 
        where TSelf : Drawable<TSelf>, IDrawable, new()
    {
        [Obsolete(FactoryMessage, true)]
        protected Drawable()
        {
        }

        public abstract void Update();
        public abstract void Draw();
    }

    internal class Rectangle : Drawable<Rectangle>
    {
        [Obsolete(FactoryMessage, true)]
        public Rectangle()
        {
        }

        public override void Update()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }

        public override void Draw()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }
    }
    internal class Circle : Drawable<Circle>
    {
        [Obsolete(FactoryMessage, true)]
        public Circle()
        {
        }

        public override void Update()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }

        public override void Draw()
        {
            GraphicsDeviceManager manager = this.Parameter;
            // TODo  manager
        }
    }


    [Test]
    public void FactoryTest()
    {
        // doesn't compile because interface abstraction is enforced.
        Rectangle rectangle = Rectangle.Create(new GraphicsDeviceManager());

        // you get only the IDrawable returned.
        IDrawable service = Circle.Create(new GraphicsDeviceManager());
    }

其他回答

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

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

如果可以在接口中定义构造函数,那将非常有用。

假设接口是一个必须以指定方式使用的契约。以下方法在某些情况下可能是可行的替代方案:

public interface IFoo {

    /// <summary>
    /// Initialize foo.
    /// </summary>
    /// <remarks>
    /// Classes that implement this interface must invoke this method from
    /// each of their constructors.
    /// </remarks>
    /// <exception cref="InvalidOperationException">
    /// Thrown when instance has already been initialized.
    /// </exception>
    void Initialize(int a);

}

public class ConcreteFoo : IFoo {

    private bool _init = false;

    public int b;

    // Obviously in this case a default value could be used for the
    // constructor argument; using overloads for purpose of example

    public ConcreteFoo() {
        Initialize(42);
    }

    public ConcreteFoo(int a) {
        Initialize(a);
    }

    public void Initialize(int a) {
        if (_init)
            throw new InvalidOperationException();
        _init = true;

        b = a;
    }

}

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

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

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对象。

接口的目的是强制某个对象签名。它不应该明确地关心对象内部如何工作。因此,从概念的角度来看,接口中的构造函数并没有真正的意义。

不过也有一些替代方案:

Create an abstract class that acts as a minimal default implementation. That class should have the constructors you expect implementing classes to have. If you don't mind the overkill, use the AbstractFactory pattern and declare a method in the factory class interface that has the required signatures. Pass the GraphicsDeviceManager as a parameter to the Update and Draw methods. Use a Compositional Object Oriented Programming framework to pass the GraphicsDeviceManager into the part of the object that requires it. This is a pretty experimental solution in my opinion.

你描述的情况一般来说不容易处理。业务应用程序中需要访问数据库的实体也有类似的情况。

如前所述,在接口上不能有构造函数。但是,由于这是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构造函数传递多个参数,可以创建一个类,为需要传递的所有字段定义属性。